Create Your Own Millisecond Delay Function Using a 12-Bit Interval Timer | Renesas RL78 - 6
Published
Hi! Welcome back again to CircuitBread. In our previous tutorial, we discussed interrupt functions and I hope you have really grasped how interrupts work because from now on we will always deal with them. In this tutorial, we will discuss the RL78 12-bit interval timer and create something that I just can’t find on the internet, a millisecond delay function for RL78 microcontrollers (MCUs).
12-bit Interval Timer Functions and Configuration
The 12-bit interval timer is one of the timers inside the RL78 MCU. It generates an interrupt when the value on its counter matches the specified time interval. The interrupt generated can be utilized for wakeup from STOP mode and triggering an A/D converter’s SNOOZE mode. But in this tutorial, we will use it to generate a delay. The configuration of the 12-bit interval timer is shown in figure 1.
Registers controlling the 12-bit Interval Timer
There are three registers involved in the 12-bit interval timer’s operation: Peripheral enable register 0 (PER0)
, Subsystem clock supply mode control register (OSMC)
, and 12-bit interval timer control register (ITMC)
.
In the PER0
register, we only need to set or clear the 7th bit, RTCEN
. RTCEN
stops or enables clock supply to the 12-bit interval timer by clearing or setting it, respectively. If RTCEN
is 0
, the 12-bit interval clock is disabled and special function registers (SFRs) used by the 12-bit interval timer can’t be written. If RTCEN
is 1
, the clock supply is enabled and the 12-bit interval timer SFRs can be read or written. After reset, the PER0
register is cleared to 00H
(hex) so by default, RTCEN
bit is 0
or the input clock supply to the 12-bit interval timer is disabled. The PER0
register can be set by a 1-bit or 8-bit memory manipulation instruction.
The next bit that we need to set is the WUTMMCK0
bit which is located at the OSMC
register. There are only two bits in the OSMC
register that we can set or clear, RTCLPC
and WUTMMCK0
bits. RTCLPC
enables or stops the supply of subsystem clock to the peripherals (other than real-time clock and 12-bit interval timer) when it is set to 0
or 1
, respectively. By default (or after reset), the OSMC
register is cleared to 00H
(hex) so we can just leave the RTCLPC
bit to 0
which will enable supply of subsystem clock to all peripheral functions that it supports.
There are two options for the 12-bit interval timer operation clock, the subsystem clock (fSUB) which is a 32.768kHz clock connected to the XT1 pin of the MCU or the 15kHz low-speed on-chip oscillator (fIL). The operation clock can be set thru the WUTMMCK0
bit of the OSMC
register. As the OSMC
is 00H
(hex) by default, this means WUTMMCK0
is 0
. The fSUB
is the default operation clock of the 12-bit interval timer.
If you are using a 30/32/36-pin RL78 device where fSUB
is not available or you didn’t connect a 32.768kHz clock to your RL78 device, you can select the 15kHz fIL
by setting WUTMMCK0
to 1
. However, the fIL
has a low accuracy of ±15%. So the fSUB
is the better option. Fortunately, the RL78/G14 FPB comes with a 32.768kHz subsystem clock.
The last register (excluding interrupt flags/bits) that we need to set is the ITMC
register. The ITMC
register is a 16-bit register where the RINTE
bit and ITCMP bits
are located.
ITCMP
, which is composed of 12 bits (ITCMP0 to ITCMP11), is where we load the value (from 001H to FFFH) that we are going to compare with the 12-bit counter of the interval timer. If fSUB
is used, 001H
will produce a 61.03us delay while FFFH
will produce 125ms.
RINTE
, which is bit 15 of the ITMC
register, stops or starts the count operation when it is set to 0
or 1
, respectively. It is the last bit that we will set to start counting after we’ve initialized the 12-bit interval timer.
12-Bit Interval Timer Operation (Interrupt)
Before we create the millisecond delay function, let’s check first how the 12-bit interval timer works using interrupt. The first thing that we need to do is create a project similar to how we created the project in this tutorial: Renesas RL78 - 3. First Project. But we will enable something under the Clock setting
tab in the code generator.
After we click the Fix settings
button under the Pin assignment
tab and disabled the watchdog timer, under the Clock setting
tab, let’s enable the fSUB
by checking the Operation
checkbox. We can just leave the default settings and then click the Generate Code
button. Don’t forget to disable Power Target From Emulator in the Debug Configurations.
So we now have the code for initializing the hardware and enabling the fSUB
. Let’s open the r_main.c
file.
Inside the r_main.c
file, we are going to add four functions: IT_Init()
, IT_Start()
, IT_Stop()
, INTIT_ISR()
. The IT_Init()
function contains the code for initializing the 12-bit interval timer. The IT_Start()
and IT_Stop()
functions are for starting and stopping the count operation of the 12-bit interval timer, respectively. The INTIT_ISR()
function is the ISR of the 12-bit interval timer.
/***********************************************************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
* No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
* applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
* LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
* ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability
* of this software. By using this software, you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclai...
*
* Copyright (C) 2011, 2021 Renesas Electronics Corporation. All rights reserved.
***********************************************************************************************************************/
/***********************************************************************************************************************
* File Name : r_main.c
* Version : CodeGenerator for RL78/G14 V2.05.06.02 [08 Nov 2021]
* Device(s) : R5F104ML
* Tool-Chain : GCCRL78
* Description : This file implements main function.
* Creation Date: 10/10/2022
***********************************************************************************************************************/
/***********************************************************************************************************************
Includes
***********************************************************************************************************************/
#include "r_cg_macrodriver.h"
#include "r_cg_cgc.h"
/* Start user code for include. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
#include "r_cg_userdefine.h"
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
void IT_Init(void);
void IT_Start(void);
void IT_Stop(void);
void INTIT_ISR(void);
/* End user code. Do not edit comment generated here */
void R_MAIN_UserInit(void);
/***********************************************************************************************************************
* Function Name: main
* Description : This function implements main function.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
PM5_bit.no2 = 0;
IT_Init();
while (1U)
{
NOP();
}
/* End user code. Do not edit comment generated here */
}
/***********************************************************************************************************************
* Function Name: R_MAIN_UserInit
* Description : This function adds user code before implementing main function.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_MAIN_UserInit(void)
{
/* Start user code. Do not edit comment generated here */
EI();
/* End user code. Do not edit comment generated here */
}
/* Start user code for adding. Do not edit comment generated here */
void IT_Init(void)
{
RTCEN = 1; /* Enable Input Clock Supply */
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
ITMK = 1; /* Mask Interval Timer Interrupt */
ITMC &= 0x0FFF; /* Stop Count Operation by Clearing RINTE bit of ITMC Register */
ITMC = 4095; /* Value (in Hex or Decimal) compared to the 12-bit counter of the interval timer. 4095 (in Decimal) will create a 125ms delay. */
/* Setting Priority Specification Flags of the 12-bit Interval Timer Interrupt to LOW */
ITPR1 = 1U;
ITPR0 = 1U;
IT_Start(); /* Starting the 12-bit Interval Timer by Unmasking ITMK, Clearing ITIF, and Setting RINTE bit to 1 */
}
void IT_Start(void)
{
ITMK = 0;
ITIF = 0;
ITMC |= 0x8000;
}
void IT_Stop(void)
{
ITIF = 0;
ITMK = 1;
ITMC &= 0x0FFF;
}
void INTIT_ISR(void)
{
IT_Stop();
P5_bit.no2 = !P5_bit.no2;
IT_Start();
}
/* End user code. Do not edit comment generated here */
So here’s our code. In line 42 to line 45
, we declared the four functions and defined them in line 84 to line 122
. Since we’re using an interrupt function here, don’t forget to declare the interrupt handler inside r_cg_interrupt_handlers.h
and r_cg_vector-table.c
as shown below.
/***********************************************************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
* No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
* applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
* LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
* ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability
* of this software. By using this software, you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclai...
*
* Copyright (C) 2011, 2021 Renesas Electronics Corporation. All rights reserved.
***********************************************************************************************************************/
/***********************************************************************************************************************
* File Name : r_cg_interrupt_handlers.h
* Version : CodeGenerator for RL78/G14 V2.05.06.02 [08 Nov 2021]
* Device(s) : R5F104ML
* Tool-Chain : GCCRL78
* Description : This file declares interrupt handlers.
* Creation Date: 10/10/2022
***********************************************************************************************************************/
#ifndef INTERRUPT_HANDLERS_H_H
#define INTERRUPT_HANDLERS_H_H
/***********************************************************************************************************************
Macro definitions (Register bit)
***********************************************************************************************************************/
/***********************************************************************************************************************
Macro definitions
***********************************************************************************************************************/
/***********************************************************************************************************************
Typedef definitions
***********************************************************************************************************************/
/***********************************************************************************************************************
Global functions
***********************************************************************************************************************/
//0x38
void INTIT_ISR(void) __attribute__ ((interrupt));
//Hardware Vectors
//0x0
void PowerON_Reset(void) __attribute__ ((interrupt));
//idle Vectors
void R_Dummy(void) __attribute__ ((interrupt));
#endif
/***********************************************************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
* No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
* applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
* LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
* ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability
* of this software. By using this software, you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclai...
*
* Copyright (C) 2011, 2021 Renesas Electronics Corporation. All rights reserved.
***********************************************************************************************************************/
/***********************************************************************************************************************
* File Name : r_cg_vector_table.c
* Version : CodeGenerator for RL78/G14 V2.05.06.02 [08 Nov 2021]
* Device(s) : R5F104ML
* Tool-Chain : GCCRL78
* Description : This file implements interrupt vector.
* Creation Date: 10/10/2022
***********************************************************************************************************************/
/***********************************************************************************************************************
Includes
***********************************************************************************************************************/
#include "r_cg_macrodriver.h"
#include "r_cg_userdefine.h"
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Set option bytes */
#define OPTION_SECT __attribute__ ((section (".option_bytes")))
const uint8_t Option_Bytes[] OPTION_SECT =
{0xEFU, 0xFFU, 0xF8U, 0x04U};
/* Set security ID */
#define SECURITYID_SECT __attribute__ ((section (".security_id")))
const uint8_t Security_Id[] SECURITYID_SECT =
{0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U};
#define VEC __attribute__ ((section (".vec")))
const void *HardwareVectors[] VEC = {
// Address 0x0
PowerON_Reset,
// Secure for Debugging
(void*)0xFFFF
};
#define VECT_SECT __attribute__ ((section (".vects")))
const void *Vectors[] VECT_SECT = {
// Address 0x4
R_Dummy,
// Address 0x6
R_Dummy,
// Address 0x8
R_Dummy,
// Address 0xA
R_Dummy,
// Address 0xC
R_Dummy,
// Address 0xE
R_Dummy,
// Address 0x10
R_Dummy,
// Address 0x12
R_Dummy,
// Address 0x14
R_Dummy,
// Address 0x16
R_Dummy,
// Address 0x18
R_Dummy,
// Address 0x1A
R_Dummy,
// Address 0x1C
R_Dummy,
// Address 0x1E
R_Dummy,
// Address 0x20
R_Dummy,
// Address 0x22
R_Dummy,
// Address 0x24
R_Dummy,
// Address 0x26
R_Dummy,
// Address 0x28
R_Dummy,
// Address 0x2A
R_Dummy,
// Address 0x2C
R_Dummy,
// Address 0x2E
R_Dummy,
// Address 0x30
R_Dummy,
// Address 0x32
R_Dummy,
// Address 0x34
R_Dummy,
// Address 0x36
R_Dummy,
// Address 0x38
INTIT_ISR,
// Address 0x3A
R_Dummy,
// Address 0x3C
R_Dummy,
// Address 0x3E
R_Dummy,
// Address 0x40
R_Dummy,
// Address 0x42
R_Dummy,
// Address 0x44
R_Dummy,
// Address 0x46
R_Dummy,
// Address 0x48
R_Dummy,
// Address 0x4A
R_Dummy,
// Address 0x4C
R_Dummy,
// Address 0x4E
R_Dummy,
// Address 0x50
R_Dummy,
// Address 0x52
R_Dummy,
// Address 0x54
R_Dummy,
// Address 0x56
R_Dummy,
// Address 0x58
R_Dummy,
// Address 0x5A
R_Dummy,
// Address 0x5C
R_Dummy,
// Address 0x5E
R_Dummy,
// Address 0x60
R_Dummy,
// Address 0x62
R_Dummy,
// Address 0x64
R_Dummy,
// Address 0x66
R_Dummy,
// Address 0x68
R_Dummy,
// Address 0x6A
R_Dummy,
// Address 0x6C
R_Dummy,
// Address 0x6E
R_Dummy,
// Address 0x70
R_Dummy,
// Address 0x72
R_Dummy,
// Address 0x74
R_Dummy,
// Address 0x76
R_Dummy,
// Address 0x78
R_Dummy,
// Address 0x7A
R_Dummy,
// Address 0x7C
R_Dummy,
// Address 0x7E
R_Dummy,
};
/***********************************************************************************************************************
* Function Name: R_Dummy
* Description : None
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_Dummy(void)
{
/* Start user code. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
}
/* Start user code for adding. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
/***********************************************************************************************************************
* Function Name: main
* Description : This function implements main function.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
PM5_bit.no2 = 0;
IT_Init();
while (1U)
{
NOP();
}
/* End user code. Do not edit comment generated here */
}
The operation of our program is shown in figure 9. As you can see, the operation is just simple. After the hardware initialization, we set the P52 pin as an output (line 59). We will connect an LED and an oscilloscope to this pin later. Then we initialize the 12-bit interval timer by calling the IT_Init()
function (line 60).
Inside the IT_Init()
function, we first set the RTCEN
bit to 1
(line 86). As mentioned earlier, setting the RTCEN
bit enables clock supply to the 12-bit interval timer and allows reading or writing to the SFRs used by the 12-bit interval timer. In line 88
and line 89
, we clear the IF flag of the 12-bit interval timer interrupt (ITIF) and mask its mask flag (ITMK), respectively. Then in line 90
, we clear the RINTE
bit of the ITMC
register to make sure that the counter is not counting.
void IT_Init(void)
{
RTCEN = 1; /* Enable Input Clock Supply */
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
ITMK = 1; /* Mask Interval Timer Interrupt */
ITMC &= 0x0FFF; /* Stop Count Operation by Clearing RINTE bit of ITMC Register */
ITMC = 4095; /* Value (in Hex or Decimal) compared to the 12-bit counter of the interval timer. 4095 (in Decimal) will create a 125ms delay. */
/* Setting Priority Specification Flags of the 12-bit Interval Timer Interrupt to LOW */
ITPR1 = 1U;
ITPR0 = 1U;
IT_Start(); /* Starting the 12-bit Interval Timer by Unmasking ITMK, Clearing ITIF, and Setting RINTE bit to 1 */
}
In line 92
, we load the maximum value that we can load to the ITCMP
bits of the ITMC
register. 0xFFF
(in hex) or 4095
(in decimal). This value according to the hardware user’s manual will generate a 125ms delay.
In line 95
and line 96
, we set the priority of the 12-bit interval timer interrupt to low by writing 1
to both of its priority specification flags (ITPR1, ITPR0). Then we start the count operation of the 12-bit interval timer by calling the IT_Start()
function (line 98).
You might wonder why there’s no line setting the WUTMMCK0
bit of the OSMC
register to select the fSUB
clock. Actually, the code for setting the OSMC
register to select the fSUB
clock was already generated by the code generator and the OSMC
register was set during the hardware or system initialization. Check the images below to see how fSUB
was set.
void IT_Start(void)
{
ITMK = 0;
ITIF = 0;
ITMC |= 0x8000;
}
The IT_Start()
function in line 101 to line 106
will just unmask the ITMK
flag (line 103), clear the ITIF
flag (line 104), and then set the RINTE
bit to 1
(line 105) which makes the count operation start.
The program will return to the main function and execute the infinite while loop which only contains a NOP()
function that does nothing.
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
PM5_bit.no2 = 0;
IT_Init();
while (1U)
{
NOP();
}
/* End user code. Do not edit comment generated here */
}
When the INTIT
interrupt occurs, the program will jump to the ISR of the 12-bit interval timer which is in line 115 to line 122
.
void INTIT_ISR(void)
{
IT_Stop();
P5_bit.no2 = !P5_bit.no2;
IT_Start();
}
/* End user code. Do not edit comment generated here */
Inside the ISR, we first call the IT_Stop()
function which is in line 108 to line 113
. The function clears the ITIF
flag (line 110), masks the ITMK
flag, and stops the count operation by clearing the RINTE
bit (line 112). Then in line 119
, we toggle the pin P52 of the RL78/G14 MCU and start the count operation of the 12-bit interval timer again by calling the IT_Start()
function in line 121
.
void IT_Stop(void)
{
ITIF = 0;
ITMK = 1;
ITMC &= 0x0FFF;
}
The program will return to the while loop inside the main function again, doing nothing until an INTIT
interrupt request signal is generated again.
Our eyes can still notice an LED blink at 125ms. So you can connect an LED to the P52 pin to see if it is really toggled. To make sure that you’re getting 125ms, you can connect the pin to an oscilloscope. I’m using Digilent Analog Discovery 2 and you can see the output waveform below.
millisecond Delay Function (Polling)
So that’s how the 12-bit interval timer works using interrupt. Now let’s create a millisecond delay function. But this time, we are going to use polling method.
Figure 13 shows the operation of our millisecond delay function, delay_ms(uint16_t delay_ms)
. As you can see, we can pass an unsigned integer to the function as its argument which will be the delay (in milliseconds).
So we call the function with the delay value and inside the function, we will first calculate the value needed to produce the delay. This value will be loaded in the ITCMP
bits of the ITMC
register later.
After the calculation, we will set the RTCEN
bit to 1
to enable the 12-bit interval timer clock supply. Next, we clear the ITIF
flag, disable the 12-bit interval timer interrupt, and set the RINTE
bit to 0
to make sure that counter is not counting. Then we load the value we calculated to the ITCMP
bits, set the RINTE
bit to 1
to start the count operation, and poll the ITIF
flag.
When the 12-bit counter value matches the value in the ITCMP
bits, the ITIF
flag will be set to 1
. In this case the program proceeds to the next steps which clears the ITIF
flag and sets the RTCEN
bit to 0
to stop the 12-bit interval timer clock supply. Then the program exits the function.
The operation above works. However, the delay that it can generate is just up to 125ms since we can only load values ranging from 1 to 4095 to the ITCMP
bits. So we are going to modify it so that it can generate delays above 125ms.
Figure 14 shows the modified operation and as you can see, after we call the delay function, it will check first if the delay value is greater than 125ms. If it’s not, then the operation is just like the operation shown in figure 13.
But if the delay is greater than 125ms, it will first enter a loop that will generate a 125ms delay for each time the body of the loop is executed. Each time the body of the loop is executed, we subtract 125 from the delay value and update the value of the delay_ms
variable which holds the delay value. Once the delay_ms
value is less than or equal to 125, the program will exit the loop. The process outside the loop will take care of the remaining value in the delay_ms
variable.
So here’s the code of the delay_ms()
function:
void delay_ms(uint16_t delay_ms)
{
while (delay_ms > 125)
{
RTCEN = 1; /* Enable Input Clock Supply */
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
ITMK = 1; /* Mask Interval Timer Interrupt */
ITMC &= 0x0FFF; /* Stop Count Operation by clearing RINTE bit of ITMC Register */
ITMC = 4095; /* Loading 125ms value to the ITCMP11 to ITCMP0 bits of the ITMC Register */
ITMC |= 0x8000; /* Start Count Operation by setting RINTE bit of ITMC Register */
while (ITIF == 0) /* Polling the ITIF flag */
{
NOP();
}
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
RTCEN = 0; /* Disable Input Clock Supply */
delay_ms = delay_ms - 125;
}
delay_ms = ((delay_ms * 32768)/1000) - 1;
RTCEN = 1; /* Enable Input Clock Supply */
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
ITMK = 1; /* Mask Interval Timer Interrupt */
ITMC &= 0x0FFF; /* Stop Count Operation by clearing RINTE bit of ITMC Register */
ITMC = delay_ms; /* Loading delay_ms remaining value to the ITCMP11 to ITCMP0 bits of the ITMC Register */
ITMC |= 0x8000; /* Start Count Operation by setting RINTE bit of ITMC Register */
while (ITIF == 0) /* Polling the ITIF flag */
{
NOP();
}
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
RTCEN = 0; /* Disable Input Clock Supply */
}
And here’s the sample code:
/***********************************************************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products.
* No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
* applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY
* LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT,
* INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR
* ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability
* of this software. By using this software, you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclai...
*
* Copyright (C) 2011, 2021 Renesas Electronics Corporation. All rights reserved.
***********************************************************************************************************************/
/***********************************************************************************************************************
* File Name : r_main.c
* Version : CodeGenerator for RL78/G14 V2.05.06.02 [08 Nov 2021]
* Device(s) : R5F104ML
* Tool-Chain : GCCRL78
* Description : This file implements main function.
* Creation Date: 12/10/2022
***********************************************************************************************************************/
/***********************************************************************************************************************
Includes
***********************************************************************************************************************/
#include "r_cg_macrodriver.h"
#include "r_cg_cgc.h"
/* Start user code for include. Do not edit comment generated here */
/* End user code. Do not edit comment generated here */
#include "r_cg_userdefine.h"
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
void delay_ms(uint16_t delay_ms);
/* End user code. Do not edit comment generated here */
void R_MAIN_UserInit(void);
/***********************************************************************************************************************
* Function Name: main
* Description : This function implements main function.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void main(void)
{
R_MAIN_UserInit();
/* Start user code. Do not edit comment generated here */
PM5_bit.no2 = 0;
while (1U)
{
P5_bit.no2 = 1;
delay_ms(500);
P5_bit.no2 = 0;
delay_ms(500);
}
/* End user code. Do not edit comment generated here */
}
/***********************************************************************************************************************
* Function Name: R_MAIN_UserInit
* Description : This function adds user code before implementing main function.
* Arguments : None
* Return Value : None
***********************************************************************************************************************/
void R_MAIN_UserInit(void)
{
/* Start user code. Do not edit comment generated here */
EI();
/* End user code. Do not edit comment generated here */
}
/* Start user code for adding. Do not edit comment generated here */
void delay_ms(uint16_t delay_ms)
{
while (delay_ms > 125)
{
RTCEN = 1; /* Enable Input Clock Supply */
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
ITMK = 1; /* Mask Interval Timer Interrupt */
ITMC &= 0x0FFF; /* Stop Count Operation by clearing RINTE bit of ITMC Register */
ITMC = 4095; /* Loading 125ms value to the ITCMP11 to ITCMP0 bits of the ITMC Register */
ITMC |= 0x8000; /* Start Count Operation by setting RINTE bit of ITMC Register */
while (ITIF == 0) /* Polling the ITIF flag */
{
NOP();
}
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
RTCEN = 0; /* Disable Input Clock Supply */
delay_ms = delay_ms - 125;
}
delay_ms = ((delay_ms * 32768)/1000) - 1;
RTCEN = 1; /* Enable Input Clock Supply */
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
ITMK = 1; /* Mask Interval Timer Interrupt */
ITMC &= 0x0FFF; /* Stop Count Operation by clearing RINTE bit of ITMC Register */
ITMC = delay_ms; /* Loading delay_ms remaining value to the ITCMP11 to ITCMP0 bits of the ITMC Register */
ITMC |= 0x8000; /* Start Count Operation by setting RINTE bit of ITMC Register */
while (ITIF == 0) /* Polling the ITIF flag */
{
NOP();
}
ITIF = 0; /* Clear 12-bit Interval Timer Interrupt Flag */
RTCEN = 0; /* Disable Input Clock Supply */
}
/* End user code. Do not edit comment generated here */
Just create a project and open the code generator. Fix settings in the Pin assignment tab, disable the watchdog timer, enable the fSUB
clock, then generate the hardware or system initialization code. Also, don’t forget to disable Power Target From The Emulator
in the Debug Configurations
. Open r_main.c
file and insert void delay_ms(uint16_t delay_ms);
between the comments generated by the code generator under Global variables and functions (see line 42). Then copy and paste the code of the delay_ms()
function between the comments generated by the code generator at the bottom part of the r_main.c
file (see line 83 to 129). Inside the main()
function, you can toggle a pin and call the delay_ms()
function to generate delays (see line 52 to line 66).
We’re done! Now we have a delay function that we can call to generate delays in milliseconds. I hope you enjoyed the tutorial and were able to follow all the steps on how to use the function in a project. If you have questions, please leave it in the comments section below or you can message us. See you in the next tutorial!
Get the latest tools and tutorials, fresh from the toaster.