Silicon Labs Silicon Labs Community
silabs.com
Language
  • 简体中文
  • 日本語
  • MCUs
    • 8-bit MCU
    • 32-bit MCU
  • Wireless
    • Bluetooth
    • Proprietary
    • Wi-Fi
    • Zigbee & Thread
    • Z-Wave
  • More Products
    • Interface
    • Isolation
    • Power
    • Sensors
    • Timing
  • Development Tools
    • Simplicity Studio
    • Third Party Tools
    • Thunderboard
  • Expert's Corner
    • Announcements
    • Blog
    • General Interest
    • Projects
  1. Community - Silicon Labs
  2. Blog

Chapter 6 Addendum: Input Modes Explained - Part 1

04/115/2017 | 10:27 PM
lynchtron

Level 5


ch6_addendum.png

 

NOTE: This is an addendum to chapter 6, so it appears out-of-order on the blog.  It covers input modes that may not be covered anywhere else in the blog series. 

 

So far, we have only used the digital input mode of the GPIO peripheral to detect a button press.  In those cases, the pin was used to provide information if the button was pressed or not pressed.  A voltage was present or it wasn’t present.  In this chapter, we will use other peripherals that are capable of detecting input signals, including analog voltages and pulses.  We can use these inputs to measure an external voltage source, or the light intensity of a light source, for example.  There are digital input peripherals that go beyond simple edge detection and can be used to count pulses, which can then be used to tell us the position or speed of rotation of a shaft.

 

This chapter aims to give you a little background into the many different ways your EFM32 MCU can sample input values.  You will learn how to pick the right peripheral for the task at hand.

Note that many of the peripherals in the EFM32 family include input pins such as I2C, USART, UART, etc.  Those peripherals are covered elsewhere, but keep in mind that is possible to use just the input pin from, say, a USART (the RX pin) and not make any use of the TX pin.  In addition, there are specialized input methods for OPAMP and LESENSE that are beyond the scope of this chapter.

 

Setup Your Project for Serial Wire Output (SWO) Console Display

Before we start experimenting with input modes, let’s set up a debug console to view the results of our experiments.  In the prior chapters, the only way to see evidence of anything happening on the Wonder Gecko Starter Kit as a result of our code was to blink an LED or examine the values of variables in Simplicity Studio’s watch window.   There is, however, a built-in console in the Simplicity Studio IDE that can make use of the standard debugging interface that you use to transfer programs to the EFM32.  This is called Serial Wire Output (SWO) and it uses the serial port protocol.  We don’t need to dive into how serial communication works in this chapter.  We will simply make use of it for displaying simple debug messages to the Simplicity Studio console through standard C library printf statements.

 

The following code can be used in any project to send printf statements to the Simplicity Studio IDE output console.

 

#include "em_device.h"
#include "em_chip.h"
#include <stdio.h>
 
int _write(int file, const char *ptr, int len)
{
    int x;
    for (x = 0; x < len; x++)
    ITM_SendChar (*ptr++);
    return (len);
}
 
void SWO_SetupForPrint(void) {
    /* Enable GPIO clock. */
    CMU ->HFPERCLKEN0 |= CMU_HFPERCLKEN0_GPIO;
    /* Enable Serial wire output pin */
    GPIO ->ROUTE |= GPIO_ROUTE_SWOPEN;
    #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_LEOPARD_FAMILY) ||         
defined(_EFM32_WONDER_FAMILY) || defined(_EFM32_GECKO_FAMILY)         /* Set location 0 */         GPIO ->ROUTE = (GPIO ->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) |    
GPIO_ROUTE_SWLOCATION_LOC0;         /* Enable output on pin - GPIO Port F, Pin 2 */         GPIO ->P[5].MODEL &= ~(_GPIO_P_MODEL_MODE2_MASK);         GPIO ->P[5].MODEL |= GPIO_P_MODEL_MODE2_PUSHPULL;     #else         /* Set location 1 */         GPIO->ROUTE = (GPIO->ROUTE & ~(_GPIO_ROUTE_SWLOCATION_MASK)) |
GPIO_ROUTE_SWLOCATION_LOC1;         /* Enable output on pin */         GPIO->P[2].MODEH &= ~(_GPIO_P_MODEH_MODE15_MASK);         GPIO->P[2].MODEH |= GPIO_P_MODEH_MODE15_PUSHPULL;     #endif     /* Enable debug clock AUXHFRCO */     CMU ->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;     /* Wait until clock is ready */     while (!(CMU ->STATUS & CMU_STATUS_AUXHFRCORDY)) ;     /* Enable trace in core debug */     CoreDebug ->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;     ITM ->LAR = 0xC5ACCE55;     ITM ->TER = 0x0;     ITM ->TCR = 0x0;     TPI ->SPPR = 2;     TPI ->ACPR = 0xf;     ITM ->TPR = 0x0;     DWT ->CTRL = 0x400003FE;     ITM ->TCR = 0x0001000D;     TPI ->FFCR = 0x00000100;     ITM ->TER = 0x1; } int main(void) {     SWO_SetupForPrint();       printf("hello world!\n");       while (1)     {     } }

Note that printf formatting (%f) is not supported by default.  To enable it, you must check the box "print floats" in Project > Properties > C/C++ Build > Settings >  GNU ARM Linker > General.

Also, note that the SWO console will not display anything until it finds a “\n” in your message string!

 

Keep in mind that you should use the printf statement sparingly.  The statements take time to run and it can disrupt the timing in your code.  Use them only during basic debugging and only during sections of code that have no timing constraints.
 
General Purpose Input Output (GPIO)

6_gpio.png

The most obvious peripheral in the MCU that can sample input pins is the GPIO.  The GPIO input modes can detect if a voltage is closer to ground or VCC and can trigger interrupts on positive or negative edges.  There are filters available to clean up glitches, and pullups and pulldowns to bias the pin high or low in the absence of external drivers.  The GPIO is the easiest input peripheral to configure and use, but should only be used for DC or low-frequency signals, perhaps under 1kHz or so.  Sampling the GPIO constantly consumes power, and interrupting the MCU on every edge requires software to take action, which keeps your software busy.  There are hardware peripherals that can automate the faster signals for you, which is what we will learn about in this chapter.

 

The following is all that is required to start sampling the state of external GPIO pin PA1.  Note that there are pullups, pulldowns, and filters available for the input mode that can be specified instead of gpioModeInput.

 

CMU_ClockEnable(cmuClock_GPIO, true);
GPIO_PinModeSet(gpioPortA, 0, gpioModeInput, 0);
bool input_state = GPIO_PinInGet(gpioPortA, 1);

More details about the GPIO peripheral can be found in Application Note AN0012 General Purpose Input Output.


Analog to Digital Converter (ADC)

6_adc.png

While the GPIO is a digital input pin, generating a value of either 0 or 1, the Analog to Digital Converter (ADC) can differentiate 4096 digital levels between ground and VCC, thanks to its 12-bit resolution.  The The ADC is available in all models of the EFM32 family of MCU’s including the Wonder Gecko.  (There are a few of the low-pin-count models that omit the ADC.)  The ADC translates the voltage present on the input pin into a digital value at a rate up to 1 million samples per second.  The ADC can therefore sample complex waveforms such as audio for processing by the MCU. 

 

There are eight input channels that can be connected to the ADC on the Wonder Gecko, each of which must be used one at a time.  Some inputs can be used in a differential manner, where one pin is the positive input and another ADC pin is the negative input, instead of using ground as the negative input. 

 

To demonstrate the operation of the ADC, we can use the ambient light sensor on the Starter Kit.  The light sensor is a transistor with the base voltage controlled by light, and it varies between 0V and 2.5V with a pulldown to ground through a 22k-ohm resistor.

6_light_sense.png

The light sensor is connected to the EFM32 on the starter kit to pins PD6 (for excitation, a DC voltage) and PC6 as an input to ACMP0.  (Keep this in mind whenever you are using these pins on the Starter Kit for another purpose!)  We can use a wire jumper to connect PC6 (pin 17 on the expansion header) to ADC channel 0 on PD0 and then measure the voltage generated by the light sensor in the ADC. 

6_adc_light_sensor.png
The following code configures the ADC for light sensing.

      CMU_ClockEnable(cmuClock_GPIO, true);
      CMU_ClockEnable(cmuClock_ADC0, true);
 
      // Set the sample rate of ADC0
      ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
      init.timebase = ADC_TimebaseCalc(0);
      init.prescale = ADC_PrescaleCalc(7000000, 0);
      ADC_Init(ADC0, &init);
 
      // Set up the ADC0 on channel0 (PD0) single-ended, referenced to 2.5V internal reference
      // Note that PD0 must be wire jumpered to PC6, since the light sensor is connected to PC6 on the starter kit
      ADC_InitSingle_TypeDef sInit = ADC_INITSINGLE_DEFAULT;
      sInit.input = adcSingleInputCh0;
      sInit.reference = adcRefVDD;
      sInit.acqTime = adcAcqTime32;
      ADC_InitSingle(ADC0, &sInit);
 
      // Excite the light sensor on PD6
      GPIO_PinModeSet(gpioPortD, 6, gpioModePushPull, 1);

 

Note that using the VDD as a reference means that the ADC readings will change as VDD changes, for example, as your battery drains.  It would be better to measure against the 2.5V or 1.25V internal references which do not change as VDD voltage changes.  This would then require your input signal to be scaled with a voltage divider.  In our example on the Starter Kit, VDD will remain stable at 3.3V, so we don’t need to take that step.

 

Once the ADC is configured, we can set up a timer to trigger an interrupt once a second, which was first explained in chapter 5. We will restart this timer after every ADC sample.

#define ONE_SECOND_TIMER_COUNT            13672
CMU_ClockEnable(cmuClock_TIMER1, true);
 
      // Create a timerInit object, based on the API default
      TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
      timerInit.prescale = timerPrescale1024;
 
      TIMER_IntEnable(TIMER1, TIMER_IF_OF);
 
      // Enable TIMER0 interrupt vector in NVIC
      NVIC_EnableIRQ(TIMER1_IRQn);
 
      // Set TIMER Top value
      TIMER_TopSet(TIMER1, ONE_SECOND_TIMER_COUNT);
 
      TIMER_Init(TIMER1, &timerInit);
 
      // Wait for the timer to get going
      while (TIMER1->CNT == 0)
            ;

 

The TIMER1 interrupt handler must be implemented to stop the timer once it triggers an interrupt and stop the timer from counting further.  As a reminder, this small function can appear anywhere in your source code, since it is declared in the EFM32 libraries and implemented in your source code.

void TIMER1_IRQHandler(void)
{
      TIMER_IntClear(TIMER1, TIMER_IF_OF);
      TIMER1->CMD = TIMER_CMD_STOP;
}

 

Finally, we can pull it all together in the main function while loop.

 

      uint32_t value;
      uint32_t last_value = 9999; // Impossible ADC value
      uint32_t sample = 0;
      while (1)
      {
            // Start an ADC aquisition
            ADC_Start(ADC0, adcStartSingle);
 
            // Wait for the measurement to complete
            while ( ADC0->STATUS & ADC_STATUS_SINGLEACT);
 
            // Get the ADC value
            value = ADC_DataSingleGet(ADC0);
 
            // Only print if the value has changed
            if ((value + ADC_NOISE) < last_value || (value - ADC_NOISE) > last_value)
            {
                  float voltage = value * 3.3;
                  voltage /= 4096.0;
 
                  // NOTE: To get floating point printing to work, you must enable "print floats" check box in:
                  // Project > Properties > C/C++ Build > GNU ARM Linker > General
                  printf("Sample #%3d ADC:%4d Voltage:%3.2f\n", (int) sample, (int) value, voltage);
            }
 
            last_value = value;
            sample++;
 
            // Wait a second before the next ADC sample
            TIMER1->CNT = 0;
            TIMER1->CMD = TIMER_CMD_START;
 
            // Sleep until the timer expires.
            EMU_EnterEM1();
      }

When you run this code, you will first see the ambient light as expressed as an ADC reading and as a calculated voltage.  As a flashlight is brought to the light sensor, the reading will change to reflect the difference in light intensity.

 

Chapter 6: Input Modes!
Sample #  0 ADC: 538 Voltage:0.43  << Room ambient light condition
Sample #  4 ADC: 500 Voltage:0.40
Sample #  8 ADC:1250 Voltage:1.01  << Light approaching the sensor
Sample #  9 ADC:3241 Voltage:2.61
Sample # 10 ADC:3954 Voltage:3.19  << Light held close to sensor
Sample # 16 ADC:1166 Voltage:0.94
Sample # 17 ADC: 461 Voltage:0.37  << Back at ambient lighting

 

IMPORTANT NOTE: DO NOT connect any ADC pin to the 5V pin on the Wonder Gecko Starter Kit!  The pins on the EFM32 are not capable of tolerating values higher than VCC + 0.3V.  If you input a voltage higher than that, you can permanently damage the input pin.  There is a “5V Reference” in the differential mode of the ADC, but this does not mean that the voltage on a single pin can exceed VCC!

 

In the test above, the ADC was only called on to perform one sample per second.   However, the ADC is capable of up to 1 million samples per second, and can therefore be used to perform complex signal analysis on analog signals.  Those techniques are beyond the scope of this chapter.

 

To save power during sleep states, the ADC needs to be stopped before entering energy modes EM2 or EM3 with the WARMUPMODE bit cleared in the ADC CTRL register.

 

More details about the ADC peripheral can be found in Application Note AN0021 Analog to Digital Converter.

 

In the next section, we will configure the Analog Comparator (ACMP) to level-shift the detected LED pulse from a weak signal to one that can be used as normal input logic to the MCU.

 

  • Blog Posts
  • Makers

Tags

  • Wireless
  • High Performance Jitter Attenuators
  • EFR32MG21 Series 2 SoCs
  • Blue Gecko Series 2
  • Zigbee SDK
  • ZigBee and Thread
  • Internet Infrastructure
  • Sensors
  • Blue Gecko Bluetooth Low Energy SoCs
  • Z-Wave
  • Micrium OS
  • Blog Posts
  • Low Jitter Clock Generators
  • Bluetooth Classic
  • Makers
  • Flex SDK
  • Tips and Tricks
  • Smart Homes
  • IoT Heroes
  • Reviews
  • RAIL
  • Simplicity Studio
  • Mighty Gecko SoCs
  • Timing
  • Blue Gecko Bluetooth Low Energy Modules
  • Clocks
  • Ultra Low Jitter Clock Generators
  • General Purpose Clock Generators
  • Industry 4.0
  • Giant Gecko
  • 32-bit MCUs
  • blue-gecko-xpress-modules
  • Bluetooth Low Energy
  • 32-bit MCU SDK
  • Gecko
  • Microcontrollers
  • News and Events
  • Industrial Automation
  • Wi-Fi
  • Bluetooth SDK
  • Community Spotlight
  • Biometric Sensors
  • General Purpose Jitter Attenuators
  • Giant Gecko S1
  • Flex Gecko
  • Internet of Things
  • 8-bit MCUs
  • Isolation
  • Powered Devices

Top Authors

  • Avatar image Mark Mulrooney
  • Avatar image Siliconlabs
  • Avatar image Nari Shin
  • Avatar image lynchtron
  • Avatar image deirdrewalsh
  • Avatar image Lance Looper
  • Avatar image lethawicker

Archives

  • 2014 December
  • 2015 January
  • 2015 February
  • 2015 March
  • 2015 April
  • 2015 May
  • 2015 June
  • 2015 July
  • 2015 August
  • 2015 September
  • 2015 October
  • 2015 November
  • 2015 December
  • 2016 January
  • 2016 February
  • 2016 March
  • 2016 April
  • 2016 May
  • 2016 June
  • 2016 July
  • 2016 August
  • 2016 September
  • 2016 October
  • 2016 November
  • 2016 December
  • 2017 January
  • 2017 February
  • 2017 March
  • 2017 April
  • 2017 May
  • 2017 June
  • 2017 July
  • 2017 August
  • 2017 September
  • 2017 October
  • 2017 November
  • 2017 December
  • 2018 January
  • 2018 February
  • 2018 March
  • 2018 April
  • 2018 May
  • 2018 June
  • 2018 July
  • 2018 August
  • 2018 September
  • 2018 October
  • 2018 November
  • 2018 December
  • 2019 January
  • 2019 February
  • 2019 March
  • 2019 April
  • 2019 May
  • 2019 June
  • 2019 July
  • 2019 August
  • 2019 September
  • 2019 October
  • 2019 November
Silicon Labs
  • About Us
  • In the News
  • Email Newsletter
  • Cookies
  • Contact Us
  • Community
  • Site Feedback
  • Investor Relations
  • Blog
  • Privacy and Terms
  • Corporate Citizenship
Copyright © Silicon Laboratories. All rights reserved.
粤ICP备15107361号-1