FB pixel

Renesas RL78 - 6. 12-bit Interval Timer and millisecond Delay Function

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.

12 bit interval timer block diagram
Figure 1. RL78 12-bit Interval Timer Block Diagram.

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.

PER0 register
Figure 2. PER0 Register with the RTCEN bit.

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.

OSMC register
Figure 3. OSMC Register RTCLPC and WUTMMCK0 bits.

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.

On chip oscillator characteristics
Figure 4. RL78 On-chip Oscillator Characteristics.

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.

ITMC register RINTE ITCMP bits
Figure 5. ITMC Register RINTE and ITCMP bits.

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.

Enable RL78 subsystem clock
Enable RL78 subsystem clock
Figure 6. Enabling the fSUB Clock and Selecting it as the 12-Bit Interval Timer Clock.

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.

R main c RL78
Figure 7. 12-Bit Interval Timer (Interrupt) Project 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

R cg interrupt handlers

/***********************************************************************************************************************

* 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 */

R cg vector table
Figure 8. Declaring 12-Bit Interval Timer Interrupt Handler.

/***********************************************************************************************************************

* 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).

12 bit interval timer interrupt operation
Figure 9. 12-Bit Interval Timer (Interrupt) Operation.

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.

R reset program
R hardware setup
screenshot of program
Figure 10. Setting 12-Bit Interval Timer Clock during Hardware/System Initialization.

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.

P52 pin oscilloscope LED
Figure 11. Connecting Pin P52 to Oscilloscope and LED.

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.

12 bit interval timer interrupt output
Figure 12. Pin P52 Output Waveform.

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.

Delay ms function flowchart less equal 125ms
Figure 13. delay_ms() function flowchart for delays less than or equal to 125ms.

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.

Delay ms function flowchart greater 125ms
Figure 14. delay_ms() function flowchart for delays greater than 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.

Modified delay ms function operation less equal 125ms
Figure 15. Modified delay_ms() function operation when delay is less than or equal to 125ms.

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.

Modified delay ms function operation greater 125ms
Figure 16. Modified delay_ms() function operation when delay is greater than 125ms.

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).

P52 output waveform 500ms delay
Figure 17. P52 Output Waveform (500ms delay).
P52 output waveform 50ms delay
Figure 18. P52 Output Waveform (50ms delay).
P52 output waveform 100ms delay
Figure 19. P52 Output Waveform (100ms delay).
P52 output waveform 1000ms delay
Figure 20. P52 Output Waveform (1000ms delay).
P52 output waveform 5000ms delay
Figure 21. P52 Output Waveform (5000ms delay).

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!

Make Bread with our CircuitBread Toaster!

Get the latest tools and tutorials, fresh from the toaster.

What are you looking for?