EFM32 Operational Amplifiers

 

1 Introduction

1.1 About

This application note explains the theory of general operational amplifiers (opamps). It also describes the opamps (OPAMP) that are built into several of the EFM32 microcontrollers. The reference manual has a section explaining how to use the OPAMPs, but this application note covers more theory, and include useful examples with a detailed analysis.

The software examples are written for the EFM32TG840F32 in the EFM32 Tiny Gecko Starter Kit.

 

2 Operational Amplifiers

2.1 Overview

Figure 2.1. A simple overview of an opamp

image

An opamp is in its simplest form an amplifier with a theoretical infinite gain. The opamp has three main terminals (see Figure 2.1 (p. 3)) which are the positive (non-inverting) and negative (inverting) inputs in addition to the output. The general formula for an opamp is given by Equation 2.1 (p. 3) , where AOL is the open loop gain which is infinite in an ideal opamp.

Amplifier Formula

VOUT = AOL (V+ - V-)                                                                            (2.1)

In addition to the three main terminals, the opamp has two power supply pins VS+ and VS-. These two voltage levels define the upper and lower voltage limit for the opamp output. Opamps also have a defined input range, which does not necessarily equal the output range. A rail-to-rail opamp is able to operate in the full range between VS+ and VS-.

 

2.1.1 Feedback

The versatility of the opamp lies in the various possible configurations that can be created by adding different feedback functions between the output and the positive and/or negative inputs. In the simplest form these feedbacks can consist of a few passive components like resistors or capacitors, but can also include more complex circuitry. These feedback connections allow many different kinds of filtering and amplification characteristics.

 

2.2 Characteristics

Open loop gain

The open loop gain (AOL) (See Equation 2.1 (p. 3) ) is the gain without positive or negative feedback. Typical values range from 20,000 to 200,000 in physical devices.

Gain bandwidth product

In a real life opamp the gain is often a tradeoff against the bandwidth the opamp will be able to handle. Because of this relation, these two factors are often presented together as the gain bandwidth product.

Input offset voltage

The output VOUT when V- = V+. This value is ideally 0, but in real-life this value is nonzero.

Slew rate

The slew rate is the maximum change of voltage the opamp can output per time unit. Normally this is very high, which means that the output voltage can change rapidly. The slew rate is typically a few V/µs.

 

2.3 Ideal Opamps

An ideal opamp is a simplified model of a physical opamp. An ideal op-amp is usually considered to have the following characteristics, and they are considered to hold for all input voltages:

• Infinite open loop gain.

• Infinite input impedance.

• Infinite slew rate.

• Infinite bandwidth.

• Zero output offset.

• Zero input offset voltage.

• Zero output impedance.

• Zero noise.

These characteristics are equivalent to the following two "golden" rules for ideal opamps:

• The opamp will output whatever makes the two inputs as equal as possible. V+ = V-.

• The inputs draw no current. I+ = I- = 0.

Ideal opamps are used when calculating quantities for physical opamps. Since physical opamps have characteristics that are close to those of an ideal opamp, this is a good approximation in most cases.

 

3 The EFM32 Operational Amplifiers

3.1 Overview

Figure 3.1. A overview of the EFM32 opamps

image

The EFM32 has up to three built in general purpose opamps, named OPA0, OPA1, and OPA2 (see Figure 3.1 (p. 5) ). It is possible to connect the three opamps together to make more complex configurations in addition to setting up either external or internal feedbacks. The feedback path for each of the opamps includes an internal resistor ladder. This ladder can be configured to set the preferred gain value. It is also possible to bypass the ladder in unity gain mode.

All the EFM32 opamps are rail-to-rail for input and output. The positive source VS+ is equal to VDD, and the negative source VS- is connected to ground. A list containing electrical characteristics of the EFM32 opamps can be found in the datasheet.

The EFM32 opamps can be calibrated. OPA0s and OPA1s offset can be set through the CH0OFFSET and CH1OFFSET bitfields respectively in DACn_CAL. The offset for OPA2 can be set through OPA2OFFSET in DACn_OPAOFFSET.

 

3.2 OPA and DAC

Figure 3.2. The DAC and its components

image

OPA0 and OPA1 are a part of the DAC, while OPA2 is separate (see Figure 3.2 (p. 6) ). All of them can be controlled from the DAC registers. OPA0 is used as an output buffer for DAC channel 0, and OPA1 is used as an output buffer for DAC channel 1. When a DAC channel is used, the associated opamp is used as an output buffer stage and the opamp can in this case not be used independently of the DAC channel. Hence, when a DAC channel is used, the corresponding opamp must be disabled. This can be done by clearing OPAxEN in DACn_OPACTRL.

 

3.3 Alternative Outputs

The outputs of all the opamps are connected to internal switches making it possible to route the outputs to various output destinations. The default output is connected directly to the DACn pin. There are several alternative outputs, these include the ADC, another opamp and different pin destinations.

 

4 The EFM32 Starter Kits

4.1 Overview of the Tiny Gecko STK

Table 4.1 (p. 7) and Figure 4.1 (p. 7) gives an overview of the available pin connections for the opamps on the EFM32TG on the Tiny Gecko Starter Kit (EFM32TG-STK3300). Notice that OPA0 and OPA1 share pins with several other devices on the PCB which in some cases will inhibit these connections to be used for the opamps. For the outputs these collisions can be solved by choosing alternate outputs as given in Table 4.1 (p. 7) . The OPA2 pin connections do not share pins with any external components, but care must still be taken with EFM32 peripherals that might be enabled on the same pins.

Table 4.1. Table showing the inputs, and the alternative outputs for all three opamps. To use OPA2, it is also possible to use the connections on the back side of the kit. The parenthesis tells which other peripherals that use the same pin.

image

Figure 4.1. The front side of the STK. The picture also shows the inputs and main outputs.

image

On the back side of the kit, there is a footprint of OPA2 (Figure 4.2 (p. 8) ). OPA2 can be accessed both from the pins on the front side (see Table 4.1 (p. 7) ), or from this footprint. The footprint has three feedback paths, two to the inverting and one to the non-inverting input. In all these three paths it is easy to connect external components like a resistor or capacitor.

Figure 4.2. The OPA2 on the back side of the STK.

image

 

4.2 Overview of the Giant Gecko STK

Table Table 4.2 (p. 8) gives an overview of the available pin connections for the opamps on the Giant Gecko Starter Kit. On the back side of the kit, there is a footprint of OPA2 which is the same as the one on the Tiny Gecko Starter Kit(Figure 4.2 (p. 8) ) and can be used in the same way. See Overview of the Tiny Gecko STK for details.

Table 4.2. Table showing the inputs, and the alternative outputs for all three opamps. To use OPA2, it is also possible to use the connections on the back side of the kit. The parenthesis tells which other peripherals that use the same pin.

image

5 Software Examples

5.1 Introduction

This chapter describes useful opamp configurations, and the theory behind them. Each of these configurations have a corresponding C software example written for the EFM32TG_STK3300. In the C-code examples where only one opamp is used, OPA2 is chosen in most of the cases. The configurations can also be adapted to OPA0 and OPA1, but they share pins with other external circuitry, so OPA2 is preferred. For more detailed information about how to set the registers to make the different configurations, see the reference manual. In all calculations the opamps are assumed to be ideal.

Opamps can be configured in many more ways than those described here. Common configurations that are not covered are differentiating amplifier, integrating amplifier, summing amplifier and current to-voltage converter.

The resistances in the figures are internal, so no external resistors or other external components are needed. Table 4.1 (p. 7) and Figure 4.1 (p. 7) gives an overview of all inputs and outputs needed to set up the configurations.

 

5.2 Unity Gain Voltage Follower

The simplest configuration with feedback is the voltage follower configuration. In this configuration only one opamp (OPA2) is used. Here the output is routed directly back to the inverting input. This configuration outputs the same voltage value as the input, VIN. This voltage follower is commonly used as a buffer to increase the drive strength to drive higher loads.

Figure 5.1. Unity Gain Voltage Follower

image

5.3 Non-inverting Amplifier

This configuration amplifies the input signal VIN. Only OPA2 is used. The gain is determined by R1 and R2 (in figure Figure 5.2 (p. 10) ) according to Equation 5.1 (p. 10) . VIN is connected to the noninverting input. In the software example R2/R1 = 1/3.

Figure 5.2. Non-inverting Amplifier

image

The inputs of the opamp do not draw any current. Let I be the current from the VOUT pin to ground. By using Ohm's law, and the ideal opamp rules, we get the following equations.

VIN = IR1 VOUT = I(R1+R2)                                                                            (5.1)

Now cancel out I, by putting the two equations together. This gives:

VOUT = (R1+R2)/R1 VIN = (1 + R2/R1) VIN                                                                         (5.2)

5.4 Inverting Amplifier

This configuration inverts the input signal VIN around the POS signal applied to the positive input according to Equation 5.5 (p. 11) . The ratio R2/R1 determines the inverting gain and unity gain is achieved when R2/R1 = 1. Then VOUT = 2POS - VIN. Only OPA2 is used in this configuration. The software example uses R2/R1 = 1.

The value of POS usually equals (VS+ + VS-)/2, giving full range on the output. For the EFM32 opamps this equals to VDD/2.

This is exactly the same configuration as the non-inverting amplifier, except that VIN is connected to the inverting input, and the non-inverting input is connected to the POS reference.

Figure 5.3. Inverting Amplifier

image

Again, let I be the current from the VOUT pin to VIN. By using Ohm's law, and the ideal opamp rules this gives the following pair of equations.

POS - VIN = IR1 VOUT-VIN = I(R1+R2)                                                                    (5.3)

Substitute out I to get

(POS-VIN)(R1+R2) = (VOUT-VIN) R1                                                                                                     (5.4)

and finally

VOUT = (POS-VIN) R1/R2 + (POS-VIN) - VIN = -(VIN - POS) R2/R1 + POS                       (5.5)

5.5 Cascaded Non-inverting Amplifier

This configuration chains several non-inverting amplifiers to create a higher overall gain. All three EFM32 opamps are used in this example. The output of OPA0 is routed to the non-inverting input of OPA1. Similarly, the output of OPA1 is routed to the non-inverting input of OPA2. If one opamp can amplify the signal by a factor of F, then this cascaded configuration can amplify by a factor of F3. In the software example F = 4/3.

Figure 5.4. Cascaded Non-inverting Amplifier

image

The mathematical analysis used to find VOUT1, VOUT2 and VOUT3 use the same idea as the single noninverting amplifier. If all resistances are like in Figure 5.4 (p. 11) , then VOUT3=(1+R2/R1)3VIN.

 

5.6 Cascaded Inverting Amplifier

This configuration consists of three inverting amplifiers put together to achieve higher accumulated gain. All three EFM32 opamps are used in this configuration. In the software example R2/R1 = 1 for all three resistor ladders.

Figure 5.5. Cascaded Inverting Amplifier

image

The mathematical analysis used to find VOUT1, VOUT2 and VOUT3 use the same idea as the single inverting amplifier. If all resistances are like in Figure 5.4 (p. 11) , then VOUT3=(1+R2/R1)3VIN.

 

5.7 Two Opamp Differential Amplifier

This configuration uses two opamps to output the weighted difference between the two inputs as shown in Figure 5.4 (p. 11) . The result is given as a differential output, VDIFF, between the two output pins given in Equation 5.9 (p. 13) . The first opamp is just used as a voltage follower, and the feedback in the second opamp is enabled. . In the software example R2/R1 = 1, so VDIFF = (V2 - V1).

As the figure shows, it is possible to use OPA0 and OPA1, or OPA1 and OPA2 to set up this configuration. The software example uses OPA0 and OPA1.

Figure 5.6. Two Opamp Differential Amplifier

image

Let VOUT be the output of OPA1 (in the upper drawing). The following equations appear by using the ideal opamp rules and Ohm's law.

(V2-V1) = IR1

VOUT-V1 = I(R1+R2)                                                                             (5.6)

Cancel out I to get

(V2-V1)(R1+R2) = (VOUT-V1) R1                                                                                  (5.7)

Solve for VOUT to get

VOUT = (R1+R2)/R1 (V2-V1) + V1 = V2 + R2/R1 (V2-V1)                             (5.8)

Now by using the fact that VDIFF = VOUT - V2

VDIFF = R2/R1 (V2-V1)                                                                          (5.9)

5.8 Three Opamp Differential Amplifier

This configuration will use all three EFM32 opamps. OPA0 and OPA1 are just used as voltage followers, and their outputs are routed to the non-inverting and inverting input of OPA2. Negative feedback is enabled in OPA2, and the non-inverting input use the OPA0 resistor ladder. The OPA0 inverting input is connected to ground. See figure Figure 5.7 (p. 13) for an overview.

Figure 5.7. Three Opamp Differential Amplifier

image

Let I1 be the current from VOUT to V1, and let I2 be the current from ground to V2. Let V be the voltage going into the two input terminals. This gives

V-V1 = I1R1

VOUT-V1= I1(R1+R2)

V- V2 = I2R1

0-V2 = I2(R1+R2)                                                                        (5.10)

Introduce R = (R1+R2)/R1. Then cancel out I1 and I2 to get

-V2 = R (V - V2)

VOUT - V1 = R (V - V1)                                                                 (5.11)

This gives

-V2 + V2R = VR = VOUT - V1 + V1R                                               (5.12)

Solve for VOUT to get

VOUT = (V2 - V1) R2/R1                                                                                        (5.13)

The Three Opamp Differential Amplifier use another set of resistances than the other configurations, and the resulting gain can be found in Table 5.1 (p. 14) .

Table 5.1. Three Opamp Differential Amplifier Gain Programming

image

5.9 Opamp to ADC

Both OPA0 and OPA1 can send their outputs directly to the EFM32 ADC. This example configures OPA1 to send its output to ADC channel 1. OPA1 will get input from the non-inverting pin and amplifies the signal by using a negative feedback. In the C-example the resistances are configured to give a gain of 4/3.

The output is routed out to the alternative OPA1 output channel, and then out to output 4, where ADC channel 1 is located. The ADC converts the signal and writes the result on the LCD display.

Figure 5.8. OPA1 Connected to the ADC.

image

5.10 DAC to Opamp

This example shows how the DAC output can be routed to OPA2. Here DAC channel 0 is used to send a signal to the positive OPA2 input. The configuration is exactly the same as the three opamp differential amplifier configuration, except that OPA0 is used as a part of DAC channel 0, and OPA1 is replaced with ground (see Figure 5.9 (p. 15) ).

Figure 5.9. DAC Connected to OPA2.

image

With R2>R1This configuration is useful for generating a higher amplitude (up to VDD) output, referenced to a lower voltage reference in the DAC conversion (e.g. internal 1.25 V bandgap reference). If R2<R1, this configuration will reduce the signal and can then be useful for outputting low amplitude signals while still utilizing the full 12-bit resolution of the DAC.

In the software example the signal is reduced from 1.0V to 0.33V.

EFM32 Low Energy Sensor Interface -Resistive sense

 

This application note covers the basics of analog and describes how to use the Low Energy Sensor Interface (LESENSE) to scan a number of resistive sensors while remaining in EM2 achieving current consumption below 2µA.

1 Introduction

1.1 LESENSE

The Low Energy Sensor Interface (LESENSE) is a peripheral which utilizes other on-chip peripherals to perform measurement of a configurable set of sensors. LESENSE uses the analog comparators (ACMP) for measurement of sensor signals together with the DAC to generate accurate reference voltages or perform sensor excitation. Figure 1.1 (p. 2)  gives an overview of the LESENSE peripheral. LESENSE consists of a sequencer, count and compare block, and a RAM block used for configuration and result storage. The sequencer handles interaction with other peripherals as well as timing of sensor measurements. The count and compare block is used to count pulses from ACMP outputs before comparing with a configurable threshold. To autonomously analyze sensor results, the LESENSE decoder provides possibility to define a finite state machine with up to 16 states, and programmable actions upon state transitions. This allows the decoder to implement a wide range of decoding schemes, for instance quadrature decoding. A RAM block is used for storage of configuration and measurement results. This allows LESENSE to have a relatively large result buffer enabling the chip to remain in a low energy mode for long periods of time while collecting sensor data. LESENSE can operate in EM2, in addition to EM1 and EM0 and can wake up the CPU on configurable events.

Figure 1.1.  LESENSE Overview

image

The LESENSE supports multiple sensor types: inductive (LC), capacitive and general analog sensors. This application note will focus on how to configure the LESENSE to read analog sensors with an example being given for a photo transistor.

 

1.2 Analog Sensors

Analog sensors are widely used in all kind of applications for measuring continuous information, unlike digital sensors which produce discrete (discontinuous) values to represent information. Some types of analog sensors include:

• Humidity

• Temperature

• Light

• Pressure

• Strain Gauge

• Potentiometers

The normal reading procedure for an analog sensor consists in applying a certain supply voltage (depending on the sensor characteristics) and reading an output voltage/current which has a mathematical relation with the measured physical quantity. Coupled to analog sensors are very commonly signal conditioning circuits which translate the sensor's electric output so it can be used by a reading device (e.g. microcontroller).

 

2 Resistive Sensing

2.1 Theory

Resistive sensors are the most basic type of analog sensors. These sensors display a change in their electrical resistance and when placed in an electric circuit such as a voltage divider or a wheatstone bridge produce a voltage signal equivalent to the measured physical quantity. Very commonly used resistive sensors include potentiometers, light sensors (photo resistors) or temperature sensors (thermistor).

 

2.2 Resistive Sense in the EFM32

The resistive sensor reading in the EFM32 can be done using either one or two pins.

 

2.2.1 One-pin Resistive Sensor Reading

Resistive sensors can be read using the LESENSE in the EFM32 using only one LESENSE pin. This means that the pin will be used for both sensor excitation and sensor reading. Because of this double role a capacitor must be placed in parallel with the sensor to hold the voltage level when the pin goes from the excitation to the measure phase (Figure 2.1 (p. 4) ).

Figure 2.1. One-pin Resistive Sensor Reading

image

Using this setup the capacitor will discharge through the sensor during the measure phase thus the discharge curve depends of the sensor resistance. The LESENSE measurement threshold has to be calibrated according to the sensor threshold that is to be measured. Figure 2.2 (p. 5)  shows the hypothetical discharge curve of a sensor on an active state (left side) and inactive state (right side).

Figure 2.2. Sensor Discharge

image

The LESENSE controls the ACMP mux for the positive channel and can also optionally control the mux for the negative input and Vdd scaling (Vth) for threshold calibration. The measurement of the discharge curve is then done by the ACMP which has an output high while the curve is above the threshold and output low when the curve drops below the threshold. The output of the ACMP is sampled in the end of the measure phase by the LESENSE indicating if the sensor is active or not.

 

2.2.2 Two-pin Resistive Sensor Reading

A resistive sensor can also be read using two pins where the alternative excitation pins (LES_ALTEXn) are used to excite the sensor. In this setup the sensor is excited also during the measure phase and a resistor divider is setup (Figure 2.3 (p. 5) ) to give a stable voltage level dependent on the sensor resistance. It is important that the excitation phase is equal or longer than the measure phase to make sure that the sensor is being excited when sampled by the LESENSE.

Figure 2.3. Two-pin Resistive Sensor Reading

image

Similarly to Section 2.2.1 (p. 4)  the ACMP is used to measure the sensor state and its output is sampled by the LESENSE in the end of the measure phase to determine if the sensor is active or not.

 

3 LESENSE

The LESENSE is an extremely configurable peripheral which allows interaction with a wide range of sensors. LESENSE is able to control the channel pins or DAC for sensor voltage excitation and the ACMP mux for sensor reading. The sensors can be excited and read using the same pin or using different pins which results in different sensor setups that can be implemented with the LESENSE. Each ACMP pin is a LESENSE channel and the number of ACMP pins yields the maximum number of LESENSE channels. By controlling the ACMP mux the LESENSE can scan through the different channels and either store the results in memory or feed them to a decoder as input for a configurable state machine (Section 3.6 (p. 9) ).

When the LESENSE interacts with sensors there are 2 main phases: excitation and measure phase. These can use either the low or the high frequency clock as timebase and the duration is adjustable in number of clock cycles. The HF clock is driven by the AUXHFRCO and the LF clock by the LFACLK branch. In addition to these there is also the option of introducing a start delay which will delay both excitation and measure phase and a measure delay which will delay the measure phase only. The relation between the different phases and associated delays is depicted in Figure 3.1 (p. 6) .

Figure 3.1. Timing diagram

image

The AUXHFRCO is controlled by the LESENSE and enabled only when needed. For short excitation or measure phase it is recommended to use the AUXHFRCO clock as timebase.

The emlib comes with a set of functions to configure the LESENSE (efm32_lesense). Using these functions it is possible to setup the LESENSE in an easier manner. This chapter will show how to use these functions to setup the LESENSE for sensor interaction.

 

3.1 LESENSE Initialization

For the initialization of the LESENSE the function void LESENSE_Init(LESENSE_Init_TypeDef const *init) can be used. This function is intended to initialize the LESENSE once in an operation cycle and configures core, timing, peripheral and decoder parameters

 

3.1.1 Core configuration

The structure type LESENSE_CoreCtrlDesc_TypeDef defines the following parameters for the core control:

Scan start mode to control how the scan start is triggered

PRS source for scan start if PRS is selected to trigger a scan

• Scan configuration register usage (e.g. direct, inverse, toggle or decoder mapping)

• Invert ACMP0 output

• Invert ACMP1 output

• Scan ACMPs simultaneously

• Store SCANRES in RAM after each scan

• Always write result buffer even if full

• Trigger condition for interrupt and DMA

• Trigger condition for DMA wakeup from EM2

• Bias mode

• Keep LESENSE running in debug mode

 

3.1.2 Timing configuration

The structure type LESENSE_TimeCtrlDesc_TypeDef defines the following parameter for timing control:

• Number of LFACLK cycles to delay sensor interaction (Start Delay)

 

3.1.3 Peripheral configuration

The structure type LESENSE_PerCtrlDesc_TypeDef defines the following parameters for peripheral control:

• DAC channel 0 data control

• Configure LESENSE conversion control on DAC channel 0

• Configure LESENSE output control on DAC channel 0

• DAC channel 1 data control

• Configure LESENSE conversion control on DAC channel 1

• Configure LESENSE output control on DAC channel 1

• Prescaling factor for the LESENSE-DAC interface

• DAC reference to be used

• LESENSE control over ACMP0

• LESENSE control over ACMP1

• LESENSE control over ACMPs and DAC warm up in idle mode

 

3.1.4 Decoder configuration

The structure type LESENSE_DecCtrlDesc_TypeDef defines the following parameters for peripheral control:

• Input for the LESENSE decoder

• Initial state of the decoder

• Check the present state in addition to the ones defined in DEFCONF

• Set interrupt flag for CHx when a transition from state x occurs

• Enable hysteresis in the decoder for suppressing changes on PRS channel 0 • Enable hysteresis in the decoder for suppressing changes on PRS channel 1

• Enable hysteresis in the decoder for suppressing changes on PRS channel 2

• Enable hysteresis in the decoder for suppressing interrupt requests

• Enable count mode on decoder PRS channels 0 and 1 to produce output which can be used by a PCNT to count up or down

• PRS channel input for bit 0 of the LESENSE decoder

PRS channel input for bit 1 of the LESENSE decoder

PRS channel input for bit 2 of the LESENSE decoder

• PRS channel input for bit 3 of the LESENSE decoder

 

3.2 Clock Prescaling

The        function LESENSE_ClkDivSet(LESENSE_ChClk_TypeDef       const      clk, LESENSE_ClkPresc_TypeDef const clkDiv) sets the prescaler value for the high and low frequency clocks of the LESENSE. The maximum prescaling values are 8 and 128 respectively and the resulting frequency is given by Equation 3.1 (p. 8) .

Prescaling equation

                                            PRESC_CLKfreq = CLKfreq / 2^PRESCvalue                                                           (3.1)

For the AUXHFRCO the PRESCvalue bitfield is AUXPRESC and for the LFACLK is LFPRESC, both in the LESENSE_TIMCTRL register.

 

3.3 Setting Scan Frequency

The function LESENSE_ScanFreqSet(uint32_t refFreq, uint32_t const scanFreq) allows to set the scan frequency for the LESENSE. The calculation is based on Equation 3.2 (p. 8)  and it does not necessarily result in the requested scan frequency due to integer division.

Prescaling equation

                                               Fscan = LFACLKLESENSE / ((1 + PCTOP) x 2PCPRESC                                                    (3.2)

 

3.4 Channel Configuration

The LESENSE       channels          can      be        configured       either   by        using    the function LESENSE_ChannelConfig(LESENSE_ChDesc_TypeDef const      *confCh, uint32_t     const      chIdx)           which   configures       a          single   channel           or LESENSE_ChannelAllConfig(LESENSE_ChAll_TypeDef const *confChAll) which configures all channels.

The structure LESENSE_ChDesc_TypeDef defines the following parameters for channel configuration:

• Enable channel scan

• Enable channel pin

• Enable channel interrupts after configuring all the sensor parameters

• Configure GPIO mode for the excitation phase of the scan sequence

• Configure channel pin setup in idle phase

• Use alternate excitation pin

• Enable channel result shift into the decoder register

• Invert result bit stored in the scan result register (SCANRES)

• Enable result storage in RAM

• Select clock for excitation timing

• Select clock for sample delay timing

• Configure excitation time

• Configure sample delay time

• Configure measure delay time

• Configure ACMP threshold

• Select ACMP output or counter output for comparison

• Configure interrupt generation mode for CHx interrupt flag

Configure decision threshold for counter

Select mode for counter comparison

To enable LESENSE to control the GPIO pins they have to be configured as push-pull. Please refer to AN0012 GPIO for more information on pin configuration.

After the LESENSE is fully configured the scan can start by using LESENSE_ScanStart() and stopped using LESENSE_ScanStop().

 

3.5 Alternate Excitation

LESENSE is able to perform sensor excitation on another pin than the one to be measured. When ALTEX in CHx_INTERACT is set, the excitation will occur on the alternative excite pin associated with the given channel. All LESENSE channels mapped to ACMP0 have their alternative channel mapped to the corresponding channel on ACMP1, and vice versa. Alternatively, the alternative excite pins can be routed to the LES_ALTEX pins. Mapping of the alternative excite pins is configured in ALTEXMAP in CTRL. Table 3.1 (p. 9)  summarizes the mapping of excitation pins for different configurations.

Table 3.1. LESENSE excitation pin mapping

image

The          alternate           excitation          pins           can          be          configured          using           the LESENSE_AltExConfig(LESENSE_ConfAltEx_TypeDef const *confAltEx) function in the emlib. The LESENSE_ConfAltEx_TypeDef parameter structure allows to:

• Select alternate excitation mapping

• Enable alternate excitation pin

• Configure idle phase setup of alternate excitation pins

• Configure if alternate excitation pins should excite for all channels or only the corresponding channel

 

3.6 State Machine

Many applications require some sort of processing of the sensor readings, for instance in the case of quadrature decoding. In quadrature decoding, the sensors repeatedly pass through a set of states which corresponds to the position of the sensors. This sequence, and many other decoding schemes, can be described as a finite state machine. To support this type of decoding without CPU intervention, LESENSE includes a highly configurable decoder, capable of decoding input from up to four sensors. The decoder is implemented as a programmable state machine with up to 16 states. When doing a sensor scan, the results from the sensors are placed in the decoder input register, SENSORSTATE, if DECODE in CHx_INTERACT is set. The resulting position after a scan is illustrated in Figure 3.2 (p. 10) , where the bottom blocks show how the SENSORSTATE register is filled. When the scan sequence is complete, the decoder evaluates the state of the sensors chosen for decoding, as depicted in Figure 3.2 (p. 10) .

Figure 3.2. Sensor scan and decode sequence

image

The decoder is a programmable state machine with support for up to 16 states. The behavior of each state can be individually configured The decoder state can be configured using the functionLESENSE_DecoderStateConfig(LESENSE_DecStDesc_TypeDef const *confDecSt, uint32_t const decSt). The structure type LESENSE_DecStDesc_TypeDef allows to configure the following parameters:

• Enable chaining the descriptor, meaning that the next descriptor pair will also be evaluated

• State condition descriptor A

• Comparator value for sensor state

• Comparator mask to exclude sensors from evaluation

• Next state to be entered if sensor state equals compare value

• PRS action to perform if sensor state equals compare value

• Set interrupt flag if sensor state equals compare value

• State condition descriptor B

• The same options as descriptor A

After configuring all the needed states it is necessary to initialize the state machine to indicate which is the initial state. This is done by writing to the LESENSE_DECSTATE register and the function LESENSE_DecoderStateGet() can be used for that purpose.

The state machine can start by using LESENSE_DecoderStart() and stopped using LESENSE_DecoderStop().

 

4 Software Example

This application note comes with a software example for resistive sensor reading which uses the light sensor in the EFM32TG STK. When using the EFM32GG STK the LESENSE channel 4 is on pin PC6. The light sensor is a photo transistor where the light intensity determines the amount of current flowing through the transistor. A resistor is then connected between the sensor emitter and ground, and the voltage drop across the resistor can be used to determine the sensor state (Figure 4.1 (p. 11) ).

Figure 4.1. Light Sensor Setup

image

The voltage drop depends on the current flowing through the resistor which is controlled by the light on the base of the transistor. Although not being a resistive sensor it behaves in the same way so it can be measured using a two pin measurement setup.

The transistor collector is connected to the alternate excitation pin (LES_ALTEX0) and the emitter and resistor node if connected to LESENSE channel 4 (ACMP0_CH4). The sensor excitation occurs during the whole measure phase.

When the sensor is triggered the user LED is lit up. In the project lightsense_single the led it lit each time the sensor triggers and in lightsense_accumulated it is lit every 5 times using the PRS and Pulse Counter (PCNT) to count the sensor triggers.

Both projects use a scanning frequency of 20Hz which results in a current consumption of 1.2µA. The current consumption goes up with scanning frequency and for 50Hz and 100Hz the current consumption is 1.6µA and 2.3µA respectively.

To estimate the LESENSE base current the scanning frequency was set to 1Hz which results in 1µA. This allows us to calculate that the current increases roughly 13nA per Hz. This is the difference between the current for 100Hz and 1Hz dividing by 100.

Although these are orientational numbers for scanning one sensor the impact of adding more sensors is the same as increasing the scanning frequency for one sensor. If one sensor is added while maintaining the same scanning frequency the result in current consumption is the same as keeping one sensor but doubling the scanning frequency.

EFM32 Interrupt Handling

This application note is an introduction to interrupts and wake-up handling in the EFM32. It includes ways to optimize for low latency wake-up, interrupt prioritization and energy saving operation.

1 Interrupt Theory

Interrupts are a commonly used technique in microcontrollers allowing CPU-external systems to indicate need for change in CPU execution. Instead of using polling loops to monitor these kinds of events and wasting valuable processing time, interrupts do not require any action from the CPU unless they are triggered.

When an Interrupt Request (IRQ) is received, the CPU will store its current state before it switches to the Interrupt Service Routine (ISR) (Figure 1.1 (p. 2) ). In older architectures there was only one ISR and SW needed to determine which source triggered the IRQ. In modern architectures like the ARM Cortex-M in the EFM32, each IRQ has its own ISR. The starting address for each ISR is stored in an interrupt vector table.

When an interrupt is triggered, the CPU automatically jumps to the corresponding address in the vector table which contains an address to the relevant ISR. The service routine then executes the tasks needed to handle the event before the CPU returns to where it left off before the interrupt was received. A common way to acknowledge the interrupt is to clear the interrupt source in the interrupt handler resulting in the IRQ being de-asserted.

Figure 1.1. Basic Interrupt Operation

image

As more than one interrupt can be triggered at the same time, interrupt priorities can be assigned to the different IRQs. This allows lower latency for the most important interrupts for real-time control etc. In interrupt controllers that support nesting, it is also possible for a high priority interrupt handler to start immediately even if another lower priority handler is executing. The CPU will then continue where it left off in the lower priority handler once it is done servicing the higher priority interrupt. Figure 1.2 (p. 3) shows an example where a higher priority interrupt (2) is serviced in the middle of the lower priority interrupt handler (1). The lookup in the vector table is done every time an IRQ is triggered, but left out in the figure for simplicity.

Figure 1.2. Nested Interrupts

image

2 Interrupts in the EFM32

The Nested Vector Interrupt Controller (NVIC) in the ARM Cortex-M processor in the EFM32 evaluates the IRQ lines and switches the CPU execution to the triggered IRQs address in the vector table. Figure 2.1 (p. 4) shows an overview of how interrupts are handled in the EFM32. Most of the peripherals in the EFM32 can generate interrupts and control one or more interrupt lines (IRQ) each.

Figure 2.1. Interrupt overview

image

2.1 Peripheral IRQ Generation

As shown in Figure 2.1 (p. 4) each IRQ line can be triggered by one or more interrupt flags (IF). Normally these interrupt flags will be set by a hardware condition (e.g. timer overflow), but SW can also set and clear these directly by writing to the IFS (Interrupt Flag Set register) or IFC (Interrupt Flag Clear register). The Interrupt Enable (IEN) register allows masking of interrupt flags that should not trigger the IRQ. To acknowledge an interrupt the Interrupt Flag corresponding to the event should be cleared (through the IFC register) in the ISR. The OR function between the interrupt flags ensures that the IRQ line is asserted as long as there are unmasked interrupt flags that have not been acknowledged. As an example, the TIMER0 peripheral contains 8 interrupt flags:

Example 2.1. TIMER0 interrupt flags/conditions

• OF - Overflow

• UF - Underflow

• CC0 - Compare Match/Input Capture on Channel 0 • CC1 - Compare Match/Input Capture on Channel 1

• CC2 - Compare Match/Input Capture on Channel 2

• ICBOF0 - Input Capture Buffer Overflow on Channel 0 • ICBOF1 - Input Capture Buffer Overflow on Channel 1

• ICBOF2 - Input Capture Buffer Overflow on Channel 2

These interrupt flags can be read through TIMER0_IF. The TIMER0_IFC and TIMER0_IFS registers are used to clear and set the interrupt flags, while TIMER0_IEN masks the flags not contributing to the IRQ. More detailed information on how to generate IRQs in the EFM32 peripherals are given in the reference manual for the device, as well as in practical examples in application notes targeted for the specific peripheral.

 

2.2 The Nested Vector Interrupt Controller (NVIC)

The Nested Vector Interrupt Controller (NVIC) is an integrated part of the ARM Cortex-M processor, supporting both Cortex-internal interrupts (Hard fault, SysTick etc.) and up to 240 peripheral interrupt requests (IRQs). In the EFM32, IRQs are generated by peripherals such as TIMERs and GPIOs as a response to events internal to, or acting upon the MCU. The NVIC's handling of the IRQs is controlled by memory mapped registers (System Control Space). More information on the NVIC can be found in the EFM32 Cortex-M3 Reference Manual.

As shown in Figure 2.1 (p. 4) , each IRQ will set a Pending bit when asserted. This pending bit will generate an interrupt request to the CPU if the corresponding enable bit (SETENA[n] in Figure 2.1 (p. 4) ) is also set. Note that the pending bit will be automatically cleared by hardware when the corresponding ISR is entered.

Table 2.1 (p. 6) shows the interrupt vector table for the EFM32TG devices. The vector table is common for all devices within the same device series (e.g. EFM32TG), but will vary between device series (e.g EFM32LG devices have a different table than EFM32G devices). The interrupts generated internally in the Cortex-M have negative IRQ numbers, while the peripheral IRQs start at 0.

Table 2.1. EFM32 Interrupts

image

2.2.1 Interrupt Priority

Each IRQ in the EFM32 has 3 bits in the Priority Level Registers (IPRn) controlling interrupt priority. A low value means a high priority. These bits are used to configure two types of priority: • Preempt priority

• Sub priority

The preempt priority level determines whether an interrupt can be executed when the processor is already running another ISR. The sub priority is only evaluated if two interrupts have the same preempt priority and are pending at the same time. The interrupt with the higher sub priority will then be handled first. If two pending interrupts have the same preempt and sub priority, the interrupt with the lower IRQ number will be handled first. By default, the priority of all interrupts is 0 (highest) out of reset. There is no need to write special wrapper code to handle nested interrupts. You only need to configure the appropriate priority for each IRQ.

The PRIGROUP bits in the AIRC Register controls how many of the priority bits are used to encode the preempt priority and how many are used for sub priority as shown in Figure 2.2 (p. 7) . By default PRIGROUP is set to 0 and all 3-bits are therefore used for preempt priority.

Figure 2.2. Definition of Priority Fields in Priority Level Register

image

2.2.2 Interrupt Sequencing

Before an ISR can be entered the CPU registers must pushed to the stack (stacking), which takes 12 clock cycles (when flash is configured to 0 wait states). Returning from the ISR also takes 12 clock cycles as the CPU state must be restored (unstacking). For ISRs following immediately after (tail-chaining), or nested inside another ISR, the ARM Cortex-M improves latency by not stacking and unstacking fully between the ISRs. This reduces the latency between the handlers to only 6 clock cycles as shown in Figure 2.3 (p. 7) .

Figure 2.3. Latency when entering interrupt handlers

image

2.3 Sleep Operation

If there is no other work for the CPU to do while waiting for an interrupt to trigger, energy can be saved by putting the CPU to sleep until the interrupt triggered. In the EFM32 there are two ways of going to sleep, the Wait For Interrupt (WFI) and the Wait For Event (WFE) instructions. After executing one of these instructions the CPU stays in sleep mode until one of the following conditions occur:

• An enabled interrupt request is asserted

• A Debug Entry request occurs, if Debug is enabled.

The SLEEPDEEP bit in the System Control Register (SCR) controls whether the processor uses Sleep or Deep Sleep/Stop Mode as its low power mode according to Table 2.2 (p. 8) . Energy Mode 4/ Shut Off Mode is entered by register commands to the Energy Management Unit (EMU) and will require a reset to wake-up thus not allowing regular interrupt operation. For more information on the functional and power consumption differences between the Energy Modes, please refer to the reference manual for the relevant EFM32 device.

Table 2.2. Entering Energy Modes with WFI/WFE

image

2.3.1 ISR Handling With Wait For Interrupt (WFI)

The Wait For Interrupt instruction (__WFI();), causes immediate entry to EM1/2/3. When an enabled IRQ is asserted, the CPU wakes up and executes the associated ISR. When the ISR is done, the main thread continues at the point it was before entering sleep mode.

 

2.3.2 Low Latency Wake-up With Wait For Event (WFE)

The Wait For Event instruction (__WFE();), causes immediate entry to EM1/2/3. The CPU will wake up once it receives an event. In the EFM32 an event can be generated by a pending interrupt if the Send Event on Pending Interrupt bit (SEVONPEND)in the System Control Register is set. Note that if the interrupt is also enabled, the pending interrupt will also cause the ISR to be executed after waking up. However, if the interrupt is not enabled, the CPU will skip the ISR and continue execution immediately from the WFE instruction. You will then be able to react to the interrupt event faster than if using the ISR as the storing of the CPU state (12 clock cycles) for the ISR is skipped. This allows wake-up in only 1 clock cycle from EM1 and only 2µs from EM2/3. Note though that the interrupt pending bit is only cleared automatically when entering the ISR, so when waking from an event without the ISR, you must first clear the interrupt flag in the peripheral and then clear the pending bit manually before entering a sleep mode again.

Whenever an event occurs, the event status register bit will be set. This is the bit that the WFE command is waiting for. It is important to note that this bit is also set when regular interrupts are executed. If this bit has been set by interrupts executed earlier in the application, and the WFE instruction is executed, the device will immediately wake up again as the event status bit is already set. This bit is not readable directly by software. To make sure that this bit is cleared, it is therefore recommended to run the following sequence before the WFE used to go to sleep:

Example 2.2. Clearing event status bit:

__SEV();                /* Set event register bit */

__WFE();               /* Clear the event status bit */

                             /* __WFE() can now be used to go to sleep */

Note that when using other interrupts at the same time as using WFE, the event status bit must be cleared every time an interrupt executes.

 

2.3.3 Continuous Sleep With SLEEPONEXIT

Normally when the ISR is done, CPU execution returns to where it left off. However, if the SLEEPONEXIT bit in the System Control Register (SCR) is set to 1 the device enters sleep (depth set by DEEPSLEEP bit) directly when finishing the ISR without returning to main. This feature is useful for applications where the program would otherwise enter sleep repeatedly between interrupts. With SLEEPONEXIT set, only one WFI instruction would need to be run and execution would not return to main until the SLEEPONEXIT bit is cleared in the ISR after a desirable condition has been met. Note that if the SLEEPONEXIT bit is changed as the last instruction in the ISR, a Data Synchronization Barrier (DSB assembly instruction) must be run to make sure that the new value is registered before the ISR is exited.

 

3 CMSIS

The ARM Cortex Microcontroller Software Interface Standard (CMSIS) is a common software standard for all Cortex-M devices across all vendors. This means that features, such as the NVIC, which are present in all Cortex microcontrollers, are handled in the same way. The example below shows an ISR for TIMER0 written according to the CMSIS standard. This function is called by the interrupt vector table, which can be found in the startup file for the device (e.g. startup_efm32tg.s).

Example 3.1. A TIMER0 ISR:

void TIMER0_IRQHandler(void) {

/* Clear the interrupt flag in the beginning */

TIMER_IntClear(TIMER0, TIMER_IF_OF);

/* More code */

}

As the NVIC is a part of the ARM Cortex-M, CMSIS functions are also provided to handle things like enabling IRQs, (done with the NVIC_EnableIRQ-function in the example below) and configuring priorities. The peripherals (like TIMER0) are not an integrated part of the Cortex and can vary from device to device. CMSIS does not dictate a set of functions for these, although a common naming standard is specified. Energy Micro does however provide a full function library for all peripherals called emlib.

Clearing of interrupt flags (TIMER_IntClear-function above) and handling of interrupt enable bits (TIMER_IntEnable-function below) are all handled by the emlib functions (functions for TIMER0 are found in efm32_timer.h). Please note that the emlib and CMSIS functions themselves are shared between all EFM32 devices and individual differences between the sub-series are handled internally in the functions.

Example 3.2. Enabling TIMER0 Overflow Interrupt:

/* Enable TIMER0 interrupt in NVIC */

NVIC_EnableIRQ(TIMER0_IRQn);

/* Enable TIMER0 IRQ on Overflow */ TIMER_IntEnable(TIMER0, TIMER_IF_OF);

4 Software examples

The included examples are written for the Tiny and Giant Gecko starter kits and their onboard devices EFM32TG840F32 and EFM32GG990F1024, respectively. Source files and projects for several IDEs are also included with this application note.

 

4.1 WFI

In the wait_for_interrupt example project, TIMER0 is set to Up/Down mode and is configured to trigger interrupts when an overflow or underflow occurs. The TOP value is set to give alternating overflow and underflow interrupts at 1 second intervals (shown in Figure 4.1 (p. 11) ). The ISR for TIMER0 checks which interrupt flag triggered and writes "OVER" or "UNDER" to the LCD display accordingly. Notice that the interrupt flag register is copied to a variable early in the ISR and then only the interrupt flags that are set are cleared. The copy of the interrupt flags is then evaluated to take appropriate action. Clearing the interrupt flags early in the ISR minimizes the time the flags are set, as other interrupt conditions occurring during this period will be lost as the flags are already set. Even though the interrupt timing in this example is predictable, this structure is still good practice and should be adhered to whenever possible.

Figure 4.1. TIMER0 in Up/Down Count Mode

image

4.2 Reduced Wake-up Latency with SEVONPEND and WFE

In the wait_for_event example project, a GPIO pin connected to a LED is toggled every time a falling edge is detected on PB0. The device is in Energy Mode 3 between GPIO interrupts. SEVONPEND is set to generate an event when the IRQ from the GPIO sets the interrupt as pending. The interrupt is not enabled, so the event will only wake-up the device from EM3 and no ISR is called. The LED is toggled immediately after the wake-up. The plot from a logic analyzer in Figure 4.2 (p. 11) shows that it takes less than 2 µs from the time the Wake-up pin goes low to the time the Wake status pin toggles. Immediately after the LED is toggled, the interrupt flag and the pending vector is cleared, making the device ready to wake up from the next event.

On the Tiny Gecko Starter Kit(EFM32TG_STK3300) the LED is located on PD7 and Push button 0 is located on PD8. On the Giant Gecko STK(EFM32GG_STK3700) they are located on PE2 and PB9, respectively.

Figure 4.2. Wake-up Latency From EM2/EM3

image

4.3 Sleep-on-Exit

The sleep_on_exit example project sets up TIMER0 in Up/Count mode to give overflow interrupts every second. The SLEEPONEXIT bit is set and the device is put in EM1. Execution will then not return to main until SLEEPONEXIT is cleared. The ISR increments an interrupt counter which is shown on the LCD every time it is run. After 5 interrupts the SLEEPONEXIT bit is cleared in the ISR and the CPU returns to main where "DONE" is written to the LCD.

 

4.4 Sub Priority

In the sub_priority example project, TIMER0 and TIMER1 are set up to start at the same time and count to 1000, triggering their overflow interrupts in the same cycle. PRIGROUP is configured so all interrupt bits are used to set sub priority. Initially both interrupts have the same default sub priority and TIMER0 ISR will then be executed first as it has the lowest numbered IRQ. Before the TIMERs reach their second overflow interrupts (also in the same cycle), the sub priority for the TIMER0 ISR has been decreased and the TIMER1 ISR will then be executed first. Both ISRs will concatenate a "0" (for TIMER0) or a "1" (for TIMER1) to a string every time they are called. The string is printed at the end of the program to show the order the ISRs were executed in.

 

4.5 Preempt Priority

In the preempt_priority example project, TIMER0 and TIMER1 are set up to trigger overflow interrupts, but they are not enabled. The TIMER0 overflow interrupt is then triggered by setting the overflow interrupt flag in SW. In the TIMER0 ISR, the TIMER1 overflow interrupt is triggered in the same way. PRIGROUP is configured so all interrupt bits are used to set preempt priority. Initially both interrupts have the same default preempt priority and the TIMER1 interrupt triggered in the TIMER0 ISR will then wait until the TIMER0 ISR finishes before starting.

Before TIMER0 overflow is triggered a second time, the preempt priority for the TIMER0 ISR has been decreased. The TIMER1 ISR will then start immediately when triggered in the TIMER0 ISR and the rest of the TIMER0 ISR will complete after the TIMER1 ISR is finished. The TIMER1 ISR will concatenate a "0" to a string every time it is called. The TIMER0 ISR will concatenate an "A" to the string before triggering the TIMER1 overflow interrupt and a "B" after. The string is printed then printed at the end of the program to show the order the ISRs were executed in. Figure 1.2 (p. 3) shows the simplified execution order of a nested interrupt.

 

4.6 Interrupt Disable

The interrupt_disable example project shows a how to disable interrupts temporarily to allow several evaluations to be done in one atomic operation, without the risk of an interrupt hitting in between to corrupt the process. In this example enabling the LFRCO and waiting for the interrupt to trigger when it is stable. In the ISR, a global variable (lfrcoReady) is set to true which is then checked in main. While this variable is false, the device is sent repeatedly to EM1. The repeated check ensures that no other interrupt triggering will incorrectly cause the program to proceed without LFRCO being ready. If this check was done without disabling the interrupts first, an LFRCO-ready interrupt firing after the check for lfrcoReady, but before the sleep instructions, could lock the whole program indefinitely as there might not be any subsequent interrupts to wake the device from sleep.

To disable and enable interrupts safely the em_int.h library is used. The library uses a lock level counter to keep track of how many times INT_Disable() and INT_Enable() has been called. INT_Disable() disables interrupts and increments the counter while INT_Enable() decrements the counter and enables interrupts only if the counter reached zero. This ensures that interrupts will not be enabled prematurely if nested disabling and enabling of interrupts is used. Notice that the CPU wakes up when the interrupt is set pending even though the global interrupts have been disabled. The ISR is however not entered until the lock level counter is decremented to zero.

 

5 Further Reading

Details on the interrupt capabilities of each peripheral in the EFM32 devices can be found in the reference manual for the device. Cortex-internal parts, such as the NVIC, is documented in the EFM32 Cortex-M3 Reference Manual. For a more narrative introduction to the Cortex-M3, "The Definitive Guide To The ARM Cortex-M3" by Joseph Yiu is recommended.