FB pixel

Renesas RA - 15. Resistance and capacitance meter using the comparator module (Part 2 - Low-power Analog Comparator, Asynchronous General Purpose Timer)

Published


Hello! This is the second part of the tutorial devoted to the analog comparators of the RA2A1 family. In the first part, we learned how to use the high-speed analog comparator for the measurement of the capacitance and the resistance. In this part, the task will be the same: receiving any character via the SEGGER RTT interface to perform a measurement of the capacitance connected to the comparator and display this capacitance in the RTT Monitor.

But I decided that it would be quite boring just to replace one comparator with another and do the same thing with it. So in this part, we also will use another type of timer that we have not considered yet. And as this timer can’t be the recipient of the ELC signal, we will get rid of the ELC as well.

So, as usual, let’s first briefly familiarize ourselves with the modules which will be used in this tutorial.

Introduction to the Low-Power Analog Comparator (ACMPLP)

The low-power comparator is quite similar to the high-speed comparator which we have considered in the first part of this tutorial but has certain peculiarities.

First of all, there are two independent low-power comparators ACMPLP0 and ACMPLP1 which nevertheless can operate together in the so-called “window mode.” This is where the joint comparators’ output is high when the input voltage is within the range between the two defined reference voltages, and is low otherwise.

The main features of the ACMPLP are:

  • Switchable analog input voltage either from the CMPINi (i = 0, 1) pin, or from the output of the internal operational amplifier.
  • Switchable reference voltage input.
    • In standard mode, it can be an internal reference voltage (1.46 V typically), input from one of the CMPREFi (i = 0, 1) pins, or output from the internal DAC8.
    • In window mode, it can be either input from CMPREFi (i = 0, 1) pins (where CMPREF0 is low reference, and CMPREF1 is high reference), or output from internal DAC8.
  • The output of the comparator can also be connected to the dedicated MCU pin. Also, changes in the output state can be monitored from the MCU register and cause the interrupt or ELC event.
  • The interrupt (and ELC event) can be generated on rising, falling, or both edges of the comparator output.
  • Digital filtering can be applied to the comparator’s outputs.
  • ACMPLP can work in high-speed mode or low-power mode in which the power consumption is reduced but the response delay is increased.

If you want to read more about this module, please refer to the corresponding chapter of the user manual.

Introduction into Asynchronous General Purpose Timer (AGT)

Previously, we have already familiarized ourselves with the RTC and GPT timers. Now let’s consider another one - AGT.

Compared to the previous two timers, this one is quite simple but it has some unique features. In the RA2A1, there are two such timers - AGT0 and AGT1. Both of them are 16-bit and can count only down from the preset max value to 0. AGT timers can work in several modes:

  • Timer mode, in which AGT works as a regular timer, clocked by one of the available internal sources, about which I will talk soon.
  • Pulse output mode, similar to the previous mode, but here the dedicated output pin toggles every time when timer underflows.
  • Event counter mode, in which AGT counts the external events applied to the dedicated input pin.
  • Pulse width measurement mode, in which the width of the external pulses applied to the same input pin as in the previous mode, is measured.
  • Pulse period measurement mode, similar to the previous one but the pulse period instead of pulse width is measured.

The count sources for the AGT are:

  • PCLKB, PCLKB/2, PCLKB/8;
  • AGTLCLK/d, AGTSCLK/d (d = 1, 2, 4, 8, 16, 32, 64, or 128). These two sources are AGT-dedicated. AGTSCLK is generated by the sub-clock oscillator, and AGTLCLK is generated by the LOCO clock. In this case, AGT can operate even when MCU is in sleep mode, that’s why it’s also called “low-power timer”;
  • underflow signal of AGT0 (which is only applicable for AGT1), this allows to cascade two timers and make them work as a single 32-bit timer.

Also, AGT has two compare registers - A and B. When the timer counter matches one of these registers, the corresponding interrupt generates. The underflow interrupt is generated when the timer counter value underflows (changes its value from 0 to the max preset value). The measurement complete interrupt is generated on the selected edge of the external pulse which parameter is being measured. All these events also generate the event signals which can be used by the ELC module as signal source.

Unfortunately, AGT can’t be used as a signal recipient for the ELC module and that’s why we got rid of the latter in the current project.

Actually, the GPT suits our current project better than AGT but I just wanted to show you that there are alternatives and they also can work.

Schematics Diagram and Algorithm of the Capacitance Measurement

Now we know a bit about the new modules that we are going to use in this project, so let’s now switch to the schematics diagram, which will differ from the previous one (Figure 1).

Figure 1 - Schematics diagram of the capacitance meter
Figure 1 - Schematics diagram of the capacitance meter

In this schematics diagram, we used the same parts as in the previous tutorial but connected them to other header pins, which makes sense as we are using other hardware modules. So the reference voltage from the divider R1-R2 goes to pin P109 which is the reference input CMPFER0 of the ACMPLP0 module. The voltage from the capacitor Cx is applied to pin P400 which is merged with the CMPIN0 pin of the same ACMPLP0 comparator.

Also, you may notice that we need to connect pins P000 and P401. As I mentioned before, AGT can’t accept signals from the ELC module but we still need to establish the communication between the comparator and timer. To do this, we configure pin P401 as the comparator output, and pin P000 as the timer external input. If we configure the timer in the pulse period measurement mode, then when the comparator’s output goes low, the timer will generate the “measurement complete” interrupt, and inside its subroutine, we can calculate the capacitance of Cx. So this is a trick - what can’t be done with the software, still can be done with the hardware.

The algorithm of the measurement of the capacitance and the end formula remains the same and can be found in the first part.

Project Creation and Configuration

Now we have everything to start with the project. So let’s open e2 studio and create a regular project based on C language using the “Bare Metal - Minimal” template.

As usual, let’s first configure the required pins. In the FSP configurator open the “Pins” tab, scroll down to the “Analog:ACMP” list, expand it, and select the “ACMPLP0” line. Then change the “Operation Mode” from “Disabled” to “Custom”, “CMPIN” from “None” to “P400”, and “CMPREF” from “None” to “P109” (Figure 2).

Figure 2 - Configuration of the ACMPLP0 pins
Figure 2 - Configuration of the ACMPLP0 pins

As you can see, there is no output comparator pin here. It’s configured separately. In the same list select “ACMP(0-1)” and change the “Operation Mode” from “Disabled” to “Custom”, and “VCOUT” from “None” to “P401” (Figure 3).

Figure 3 - Configuration of the analog comparator output
Figure 3 - Configuration of the analog comparator output

As you can see, this output is common for all comparators and is OR’d with the other outputs.

Now let’s expand the “P5” list and select the “P502” pin the same as we did in the previous part. Here we change its mode from “Disabled” to “Output Mode (Initial High)”, also we set the “Symbolic Name” as “CHARGE_CONTROL” (Figure 4).

Figure 4 - Configuration of the P502 pin
Figure 4 - Configuration of the P502 pin

Now we need to configure the input pin of the AGT timer. To do this, we need to scroll down and expand the list “Timers:AGT” and select the “AGT1” line. We don’t select “AGT0” just because all its possible input pins are already used by other hardware, and “AGT1” still has some unused options. So in the opened table, we (as usual) change the “Operation Mode” from “Disabled” to “Custom”, and “AGTIO” field from “None” to “P000”. We don’t need other pins, so let’s leave them unchanged (Figure 5).

Figure 5 - Configuration of the AGT1 input pin
Figure 5 - Configuration of the AGT1 input pin

Now all required pins are configured, so we can switch to the “Stacks” tab to add and configure the required stacks.

First, let’s add the new ACMPLP stack from the “Analog” list which is called here as “Comparator, Low-Power (r_acmplp)” (Figure 6).

Figure 6 - Adding the ACMPLP stack
Figure 6 - Adding the ACMPLP stack

Now let’s select the new block “g_comparator0 Comparator, Low-Power (r_acmplp)”, and configure it according to Figure 7.

Figure 7 - Configuration of the ACMPLP stack
Figure 7 - Configuration of the ACMPLP stack

Let’s consider what the parameters of this module mean.

  • “Name” is the name of the module by which it will be used in the program. We can leave it as the default “g_comparator0”.
  • “Channel” selects the hardware channel of the comparator. As I said before, there are two channels available, but as we already have configured the pins for channel 0, let’s leave it here as well.
  • “Mode” allows the user to select between the “Standard” mode, in which each comparator works as normal, and the “Window” mode, in which two comparators work together, and the joint output is high when the input voltage lays within the given reference voltages range. Here we will use the “Standard” mode.
  • “Trigger” sets the comparator output edge at which the interrupt and/or the ELC event will be generated. According to the algorithm of the capacitance measurement, we need to register the falling edge, so we select this option.
  • “Filter” selects the PCLK divisor for the hardware digital debounce filter. Larger divisors provide a longer debounce and take longer for the output to update. As we expect the capacitor discharge curve to be smooth, we disable this filter.
  • “Output Polarity” allows to invert the output polarity, so if the input voltage is lower than the reference voltage, the output will be high, and vice versa. This value also affects the trigger edge. We will leave the output polarity as “Not Inverted” not to confuse ourselves.
  • “Pin Output (VCOUT)” allows connecting the output of the comparator to the physical output pin of the MCU. This time we will use this feature, we change it to “Enabled”.
  • “Vref (Standard mode only)” allows using the internal reference voltage (about 1.46V) as the comparator’s reference. As we will apply the reference voltage from the R1-R2 divider, we leave this option “Disabled”.
  • “Callback” sets the name of the callback function if the comparator interrupt is enabled. As we are not going to use it, we leave this value as “NULL”.
  • “Comparator Interrupt Priority” sets the priority of the comparator interrupt (obviously). If this field is set as “Disabled”, the interrupts are also disabled. Let’s leave it like that.
  • “Analog Input Voltage Source (IVCMP)” selects the pin to which the input voltage of the comparator will be applied (CMPIN0 or CMPIN1) or the operational amplifier whose output is used as the input voltage for the comparator (AMP0O or AMP1O). As we connected the capacitor circuit to the CMPIN0 pin (see Figure 1), we used this option.
  • “Reference Voltage Input Source (IVREF)” selects the source of the reference voltage. It can be either the MCU pin (CMPREF0 or CMPREF1) or the internal source (DAC8 DA0, DAC8 DA1). As we use the external voltage divider R1-R2 as the reference voltage source, connected to the pin CMPREF0/P109 (see Figure 1), we selected the option “CMPREF0”.

Also, make sure that VCOUT, CMPIN, and CMPREF pins correspond to Figure 7.

For more information about the high-speed comparator stack, please refer to this Renesas GitHub page.

Now let’s add the AGT stack. Click on the “New Stack”, expand the “Timers” list, and select the “Timer, Low-Power (r_agt)” line (Figure 8).

Figure 8 - Adding the AGT stack
Figure 8 - Adding the AGT stack

As usual, we now need to select the new block “g_timer0 Timer, Low-Power (r_agt)”, and configure it according to to Figure 9.

Figure 9 - Configuration of the AGT stack
Figure 9 - Configuration of the AGT stack

Let’s briefly consider the meaning of the parameters of the AGT stack:

  • “Pin Output Support” should be enabled if you are going to output the pulses from the timer to the MCU pin. As we’re not going to use this functionality, we leave it disabled.
  • “Pin Input Support” should be enabled to use pulse width measurement mode, pulse period measurement mode, or input from P402, P402, or AGTIO. As we are going to operate in the pulse period measurement mode, we need to change this option to “Enabled”.
  • “Name” is the name by which the module is known by the program. As we are using AGT1, let’s change the name from “g_timer0” to “g_timer1”.
  • “Channel” sets the physical AGT channel. As I just mentioned, we are using AGT1, so we must change the channel from “0” to “1”.
  • “Mode” sets the mode in which AGT will operate. Possible options are “Periodic”, in which the timer will reload automatically after each underflow, “One-shot”, in which the timer will be stopped after the first underflow (for AGT this feature is not supported by the hardware, so it’s emulated in software in the interrupt subroutine), and “PWM” which outputs the PWM signal to the selected output pin.
  • “Period” specifies the timer period based on the selected unit. When the unit is set to “Raw Counts”, setting the period to 0x10000 results in the maximum period at the lowest divisor (fastest timer tick). Set the period to 0x10000 for a free running timer, pulse width measurement, or pulse period measurement. Setting the period higher will automatically select a higher divider; the period can be set up to 0x80000 when counting from PCLKB or 0x800000 when counting from LOCO/subclock, which will use a divider of 8 or 128 respectively with the maximum period.
  • “Period Units” sets the units of the period specified above. Like for GTP, it can be “Raw Counts”, “Nanoseconds”, “Microseconds”, “Milliseconds”, “Seconds”, “Hertz”, and “Kilohertz”. We select the “Raw Counts” for the reasons specified above.
  • “Count source” selects the clock source of the timer. I already encountered them in the description of the AGT module. Here we need to select the “PCLKB” as the high-speed clock for higher accuracy of the capacitance calculation.
  • “Output” list consists of the parameters used in the PWM mode to output the pulses via the dedicated pins. As we’re not using it in our program, I will skip its detailed explanation for now.
  • “Measurement Mode”' selects if the AGT should be used to measure pulse width or pulse period. In high-level pulse width measurement mode, the AGT counts when AGTIO is high and starts counting immediately in the middle of a pulse if AGTIO is high when R_AGT_Start() is called. In low-level pulse width measurement mode, the AGT counts when AGTIO is low and could start counting in the middle of a pulse if AGTIO is low when R_AGT_Start() is called. In our case, we will use the “Measure Pulse Period” option. Even though we don’t need the whole period length, in this mode the interrupt is generated at the specified edge at the input pin, which is exactly what is needed.
  • “Input Filter” applies AGTIO in pulse period measurement, pulse width measurement, or event counter mode. The filter requires the signal to be at the same level for 3 successive reads at the specified filter frequency. Here we need to change it from the default “No filter” to the “Filter sampled at PCLKB/8”. For some reason, the comparator output turned out to be quite noisy, or maybe the other hardware connected to pins P000 and P401 interferes with the comparator signal. Anyway, the output is noisy, and without a filter, there were false triggers that caused wrong calculations, so I selected the least possible period, at which the results are stable.
  • “Enable Pin” selects the active edge for the AGTEE pin if used. This only applies if the count source is P402, P403, or AGTIO. As we’re not using the AGTEE pin, we leave this option as “Enable Pin Not Used”.
  • “Trigger Edge” selects the edge at the AGTIO pin at which the “measurement complete” interrupt will be generated. As we have already agreed, we need to determine the falling edge at the comparator output, so we select the “Trigger Edge Falling” option.
  • “Callback” sets the name of the callback function of the timer. As we are going to use the “measurement complete” interrupt (and actually the underflow interrupt as well), we need to change this field from “NULL” to some name. I selected “timer1_callback” but you can choose whatever you’d like.
  • “Underflow Interrupt Priority” selects the priority for the timer interrupt. For AGT interrupts are not distinguished at this stage, so all of them are enabled when you enable this option. So we change it from “Disabled” to “Priority 1” (actually in this project the priority number doesn’t matter, as there is only one active interrupt).

Again, make sure that the AGTIO pin is assigned to P000.

For more information about the AGT stack, please refer to this page.

And now the stack configuration is completed.

Now let’s switch to the “Clocks” tab and check what the frequency is of the PCLKB signal which is used for clocking the AGT timer. In our case, it’s 24 MHz (Figure 10). We need to remember this value, we will use it in further calculations of the capacitance.

Figure 10 - Clocks configuration
Figure 10 - Clocks configuration

Now that’s really it, so we click the “Generate Project Content” button and switch to writing the program code.

Program Code of the Project

Before we proceed with creating our own code, we need to add the files for supporting the RTT. I have explained in detail how to do this in the previous part of the tutorial, so please refer to it. Also, if you follow all the tutorials, you can just copy and paste the RTT-related files from the previous project into the current project.

And now we can open the “hal_entry.c” file and write the program code.

#include "hal_data.h"

#include "SEGGER_RTT.h"

FSP_CPP_HEADER

void R_BSP_WarmStart(bsp_warm_start_event_t event);

FSP_CPP_FOOTER

volatile uint32_t capacitance; //Calculated capacitance

volatile uint8_t measurement_done; //Indicates that the measurement is completed

static int key; //The character read from the RTT

void timer1_callback (timer_callback_args_t * p_args) //Timer1 callback

{

if (TIMER_EVENT_CYCLE_END == p_args->event)

{

/* An underflow occurred during capture. This must be accounted for at the application layer. */

capacitance += 65536; //Add the timer period to the capacitance

}

if (TIMER_EVENT_CAPTURE_A == p_args->event) //If event is "Capture A"

{

capacitance += p_args->capture; //Add the last portion of the timer ticks

capacitance = capacitance * 25 / 6; //Then calculate the capacitance

measurement_done = 1; //And indicate that measurement is done

}

}

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

* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function

* is called by main() when no RTOS is used.

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

void hal_entry(void)

{

comparator_info_t info; //Variable to get the comparator info

char units[3] = "pF"; //Units of the capacitance to send to RTT

R_AGT_Open(&g_timer1_ctrl, &g_timer1_cfg); //Initialize Timer 1

R_AGT_Enable(&g_timer1_ctrl); //Enable external events at Timer 1

R_AGT_Start(&g_timer1_ctrl); //Start the counting of Timer 1

R_ACMPLP_Open(&g_comparator0_ctrl, &g_comparator0_cfg); //Initialize the comparator

R_ACMPLP_InfoGet(&g_comparator0_ctrl, &info); //Get the comparator info

R_BSP_SoftwareDelay(info.min_stabilization_wait_us, BSP_DELAY_UNITS_MICROSECONDS); //Wait while the comparator is stabilized

R_ACMPLP_OutputEnable(&g_comparator0_ctrl); //Enable the comparator's 

output

SEGGER_RTT_printf(0, "Press any key to start measurement"); //Send the prompt text to RTT

while (1)

{

R_BSP_PinAccessEnable(); //Enable access to the IO registers

R_BSP_PinWrite(CHARGE_CONTROL, BSP_IO_LEVEL_HIGH); //Set the CHARGE_CONTROL pin high to charge the capacitor

R_BSP_PinAccessDisable(); //Disable access to the IO registers

R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS); //Wait for at least a second while capacitor is being charged

key = SEGGER_RTT_WaitKey(); //Wait for any key from the RTT

R_AGT_Reset(&g_timer1_ctrl); //Reset the Timer 1 counter

R_BSP_PinAccessEnable(); //Enable access to the IO registers

R_BSP_PinWrite(CHARGE_CONTROL, BSP_IO_LEVEL_LOW); //Set the CHARGE_CONTROL pin low to start the capacitor discharge

R_BSP_PinAccessDisable(); //Disable access to the IO registers

capacitance = 0; //Assign 0 to the capacitance

measurement_done = 0; //Reset the measurement_done variable

while (!measurement_done); //Wait while measurement is done

if (capacitance < 1000000) //If capacitance is less than 1 uF

units[0] = 'p'; //Then set the units pF

else //Otherwise

{

capacitance /= 1000; //Divide the capacitance by 1000

units[0] = 'n'; //And set the units nF

}

SEGGER_RTT_printf(0, "C = %u %s", capacitance, units); //Send the capacitance value to RTT

}

#if BSP_TZ_SECURE_BUILD

/* Enter non-secure code */

R_BSP_NonSecureEnter();

#endif }

If you compare this program with the first half of this tutorial, you may notice that they are very similar. This is the big advantage of the FSP - even though we use different types of timers and comparators, the functions with which we deal with them are almost the same. Here I will provide the full description of the program, but the majority of it will be copied and pasted from the previous part.

In line 8 we declare the variable capacitance which represents the capacitance of the measured capacitor in pF.

In line 9 we declare the variable measurement_done which is the flag that indicates that the measurement of the capacitance is complete.

In line 10 there is the declaration of the last global variable key, into which we will copy the character received via the RTT.

In lines 12-26 there is an AGT1 callback function “timer1_callback” the name of which we have defined during the AGT configuration (Figure 9). This function has a single parameter p_args of type timer_callback_args_t which consists of the callback event type and the captured value which we will need to calculate the capacitance.

In line 14 we check if the event that caused the interrupt was TIMER_EVENT_CYCLE_END. This event is generated on timer underflow. As we now have a 16-bit timer instead of a 32-bit, it can underflow several times while the capacitor is being discharged. If we don’t take this into account, we always will get only small values of the capacitor limited with 16-bit timer values. So if underflow has happened we need to add the timer period to the capacitance value (line 17) which now just represents the number of timer ticks since the beginning of the capacitor discharge. This period is 0x10000 or 65536 (as we set in Figure 9).

In line 20 we check if the event that caused the interrupt was TIMER_EVENT_CAPTURE_A. For AGT, this is an emulated event because it doesn’t support the capture functionality and doesn’t have the capture A register. In this case, this event corresponds to the “Measurement complete” interrupt which happens when the comparator output goes low.

In line 22 we add the captured value to the capacitance variable. Warning! This value is already swapped, so you don’t need to do it again. What I mean is, that AGT counts down from its max value to 0, so if the captured value is 10,000, you could think that the timer has already counted from 65,536 down to 10,000, but in fact, it’s not so. 10,000 here means the number of ticks from the beginning of the last period, so the actual timer counter value is 55,536.

In line 23 we calculate the capacitance using almost the same formula as in the previous part:

capacitance = (capacitance * 25) / 6;

Before line 23 the capacitance value is the number of AGT1 ticks since the beginning of the capacitor discharge. Now we need to convert it into seconds. Earlier, I pointed your attention to the timer clock frequency which is 24 MHz (Figure 10), and now the time has come to use it.

So each timer tick takes

Also, the resistance R3 is 10kOhm (Figure 1). Let’s put these values into the capacitance formula:

If we calculate the capacitance in pF which is 10-12 of F, then the formula will be changed:

Now we can divide both numerator and denominator by 4, and finally, we will receive:

>

Which exactly corresponds with line 23. Actually, we could decide not to divide the fraction by 4 but in this case, we can overflow the 32-bit capacitance value if the capacitor is large enough

By this division, we can expand the measurement range 4 times, up to 170F. Also, you can change the measurement range by using different values of the resistor R3. If you use a greater resistance, you can measure smaller capacitance and vice versa. But let’s now return to the program.

After line 23 we have the capacitance value in pF. In line 24 we assign 1 to the measurement_done variable to indicate that the measurement is completed. We will need this information further in the main loop of the program.

In lines 32-77, there is the main function of the program hal_entry. Traditionally, it starts with the initialization part (lines 34-46).

In line 34 we declare the local variable info which is used to get the information about the low-power comparator in line 42.

In line 35 we declare the array of char which will contain the units of the measurement of the capacitance. By default let’s initialize it with the string “pF”.

In lines 37-39, we initialize AGT1. In line 37 we open the timer stack. Then in line 38, we enable the external trigger events by calling R_AGT_Enable function. In line 39 we start the timer, after which it increments its counter continuously every PCLKB clock tick.

In lines 41-44, we initialize the low-power comparator. Usually, we first open the stack (line 41). Then we get the comparator information by invoking the function R_ACMPLP_InfoGet (line 42). This function has two parameters - the pointer to the comparator control variable, and the pointer to the comparator_info_t structure into which the information will be copied. This structure has the single field min_stabilization_wait_us which represents the minimum time required for the comparator’s parameters to stabilize. So before proceeding, we should perform the delay for this time, which we do in line 43. Finally, in line 44 we enable the comparator output by invoking the function R_ACMPLP_OutputEnable. After that, the comparator output becomes available. It can be polled with the application and it can generate the events for the ELC module and interrupts. Also, if the physical output pin is enabled, it will change its state as well.

In line 46 we invoke the function SEGGER_RTT_printf which sends the message via the RTT that tells the user what to do to start the conversion.

This is actually all about the configuration part. In lines 48-71, there is the main loop of the program. First, we set the CHARGE_CONTROL pin (P502) high (lines 50-52) to charge the capacitor Cx through the resistor R3 (Figure 1). This process takes some time, so we perform a 1-second delay (line 53) to fully charge the capacitor.

Now the capacitor keeps charging for an indefinite time while any key is pressed and sent via RTT. In line 55 we invoke the function SEGGER_RTT_WaitKey. This function waits until at least one character is available in the SEGGER RTT buffer. Once a character is available, it is read and this function returns.

Once we receive the character from the RTT, we reset the AGT1 counter by invoking the function R_AGT_Reset (line 56) and simultaneously set the CHARGE_CONTROL pin low (lines 57-59). We also need to assign 0 to the capacitance variable (line 60), as now it’s the accumulating value.

So AGT1 counts the time from the beginning of the capacitor discharge until the moment when the voltage on it reaches

of AVCC0. After the discharge has started, we reset the flag measurement_done (line 61) and wait while it becomes 1 (line 62). This happens when the comparator’s output goes low and triggers the “measurement completer” event of AGT1, whose interrupt subroutine is processed in lines 12-26. Inside this subroutine, as I described before, the measurement_done flag is set in line 24.

In lines 63-69, we configure the capacitance value and its measurement units. If the capacitance is lower than 1,000,000 pF (line 63) we set the units as pF (line 64) and use the capacitance value as is. Otherwise, we divide the capacitance by 1000 (line 67) and set the units as nF (line 68).

Finally, we send the capacitance and its units via the RTT using the SEGGER_RTT_printf function (line 70).

And that’s actually all about the program code. As I said initially, it’s quite simple and straightforward. Now let’s assemble the circuit according to the schematics diagram (Figure 1). As for Cx, I will use the same seven capacitors that I used in the first part: five ceramic ones (300 pF, 10 nF, 330 nF, 1.5 uF, and 10 uF) and two electrolytic ones (10 uF and 47 uF). I will connect them one by one to measure their values, starting with the capacitor of 300 pF.

The connection to the RTT Viewer and the program operation is absolutely the same as in the first part of this tutorial, so I will skip it here. Actually, if you don’t know exactly which program you run, you can’t guess it from the RTT Viewer perspective. Here I will just provide the results of the measurement of the capacitances and compare them with the values from the previous part

Table 1 - Results of the Capacitance Measurements

Nominal value

Measured value (ACMPHS)

Measured value (ACMPLP)

300 pF (ceramic)

287 pF

595 pF

10 nF (ceramic)

11.5 nF

11.3 nF

330 nF (ceramic)

370 nF

347 nF

1.5 uF (ceramic)

1.46 uF

1.3 uF

10 uF (ceramic)

3.18 uF

2.47 uF

10 uF (electrolytic)

10.7 uF

10.6 uF

47 uF (electrolytic)

49 uF

48.6 uF

As you can see, the majority of the results match with the reasonable tolerance but all the results taken by the low-power comparator are lower than the ones obtained by the high-speed comparator. I frankly don’t know what is the bottleneck in this case, and even what results are more precise. The only big difference is the value of the capacitor with the nominal value of 300 pF. I think this is caused by the enabled digital filtering when using the ACMPLP+AGT because changing the filter period changed the capacitance as well (you can check this yourself). So as you see, there is some lower limit below which the calculations become incorrect in the case of using the set ACMPLP+AGT.

And that's all for this part. In this tutorial, we have familiarized ourselves with the analog comparators of the RA2A1 family, event link controller, and asynchronous general-purpose timer. Also, we have learned how to send and receive data via the SEGGER RTT.

As homework for this part, I suggest you change the filter periods of AGT and ACMPLP stacks and see how they affect the measurement results. It’s probably better to enable the filtering at the comparator instead of the timer, or probably it’s better to use a lower period but use both filters. So try several variants and share your results in the comments below this tutorial.

Next time we will learn how to work with the DAC modules. See you soon!

Make Bread with our CircuitBread Toaster!

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

What are you looking for?