📜 ⬆️ ⬇️

Article about microcontroller EFM32ZG110F32

It just so happened that we had quite a lot of EFM32ZG110F32 microcontrollers in stock, this is a Zero Gecko series from SiLabs. The controllers are cool, but not very popular yet, that's why I'm writing this article.


As an advertisement, we offer the following set: ARM Cortex-M0 +, 32 Kbytes of Flash, 4 Kbytes of RAM, DMA, I2C, UART, USART, 12-bit ADC, current DAC, comparator, hardware pulse counter, real time clock and various pieces to reduce power consumption in the QFN-24 package for $ 0.96 .
upd: yes, it is possible by the piece

Under the cut a long post with a detailed overview of the crystal and the debug board, a description of the available programming and debugging tools. Examples of working with various peripheral crystal blocks are given, proprietary development tools and the mbed platform from ARM are used.
')

Hardware overview



EFM32 is a 32-bit microcontroller based on ARM Cortex-M processor cores. Their main feature is the support of a variety of software and hardware technologies to optimize power consumption, but at the same time a standard set of peripheral devices is also provided.

The hero of this article - the EFM32ZG110F32 microcontroller - belongs to the youngest series of the EFM32 family, it is called the EFM32 Zero Gecko. These are the simplest and cheapest controllers under the EFM32 brand, they are built on the basis of the Cortex-M0 + core and differ in the set of supported peripherals and enclosures. The fact that represents the EFM32ZG110F32, the easiest way to judge by this scheme.



The color for each block indicates the power consumption mode, up to which the block can be used:


In order to evaluate the described microcontroller, it is most convenient to use a debug board and in this article the possibilities of the crystal will be demonstrated precisely with its help. The EFM32 Zero Gecko microcontroller kit is called EFM32ZG-STK3200 and is purchased for $ 42, please contact. The kit consists of a USB cable, a battery and one such board.



Here it is important to note this: the article is devoted to the EFM32ZG110F32 microcircuit, and on the debug board there is a more “older” microcontroller of the same series - EFM32ZG222F32. The first controller is made in the QFN-24 package, the second - in the QPF-48. As a result, only 17 I / O lines are available on the EFM32ZG110F32, up to five of which can be used as ADC channels, and on the EFM32ZG222F32 there are already 37 lines, of which only two are potential channels for the ADC. The rest of the crystals are completely identical, so the examples discussed below can be safely attributed to both EFM32ZG222F32 and EFM32ZG110F32.

Now back to the debug board and consider the modules available on it:


If your application is designed for a task in which power consumption is important, then the EFM32ZG-STK3200 is absolutely useful for you (primarily due to the Advanced Energy Monitor measurement module mentioned above). If the EFM32 is not used in a battery-powered device, and for some reason you don’t want to use this board at all, you still have to link to Zero Gecko Starter Kit Schematics. It may well come in handy when designing.

From the review of the microcontroller and the debug board, we turn to the review of the available software development tools.

Software Review



For development, you can use both software from Silicon Labs, and commonly used gcc or Keil, IAR, etc.

Silicon Labs platform is called Simplicity Studio. It includes an eclipse-based IDE, several utilities for developing and debugging a project, sample programs, all documentation and other components. It makes sense to use either Simplicity Studio only, or your familiar development environment (Keil, IAR, Atollic, Rowley or Sourcery) or gcc along with utilities from Simplicity Studio.

Why is it worth downloading Simplicity Studio regardless of your preferred compiler and IDE?
First, it does not cost anything. Like any other software from manufacturers of microcontrollers, Simplicity Studio is a free environment. Secondly, distributions are available for Mac and Ubuntu. Thirdly, when installing Simplicity Studio for the selected family of microcontrollers (in our case for 32-bit EFM32), you will immediately receive a complete set of development tools, documentation and useful links that will be automatically updated. It's comfortable.

So, after installing Simplicity Studio and connecting the debug board (on which USB power should be selected), the main menu of the program will appear.



All displayed tools are active for the connected microcontroller. If, for example, a Zigbee module were chosen, then a completely different set of icons would result. The following options are available for debugging the program on EFM32ZGxxx:

In the upper right corner there is an update center, where you can check and download all available software updates and documentation for the selected series of microcontrollers.

Speaking of updates. The first Simplicity Studio, developed by the company energy micro, was great in its simplicity. The next version was released in Silicon Labs. Simplicity Studio 2.0 had a much wider range of functions, contained an IDE and supported C8051Fxxx microcontrollers, but it turned out to be very slow. By the current version (3.2), the situation is completely leveled and working in Simplicity Studio is again very nice.

To acquaint the reader with the capabilities of the EFM32ZG110F32 microcontroller, consider several examples of working with various development and debugging tools.

Example # 1 Readiness Check



If the debugging board was in your hands for the first time and you just launched Simplicity Studio, then it makes sense to run a demo example and make sure that all this software and hardware complex is working properly.
After switching on the board in DBG mode, make sure that the board has been determined (see the lower left corner of the main menu of Simplicity Studio). For the EFM32ZG-STK3200 card in the first row, the Demo item will be available, containing ready-made firmware for the microcontroller.



You just need to select one of the projects and click Finish. The controller will be programmed with a ready-made binary file, the selected program will start on the board, and a graph of the current consumption level will appear on the computer screen.
If everything went well, then you can start developing your own programs.

All demo programs are available in the form of projects for each of the supported development environments. The corresponding files after installing Simplicity Studio are in the directory ... \ SiliconLabs \ SimplicityStudio \ v3 \ developer \ sdks \ efm32 \ v2 \ kits \ EFM32ZG_STK3200 \ examples

For each example available:


Example # 2 Working with the Low Energy UART interface and the energy profiler utility



Let's start to deal with individual units of the microcontroller. Returning to the peripheral block diagram of the EFM32ZG110F32 microcontroller, you can notice the LEUART module among the communication interfaces.
LEUART or Low Energy UART is a serial interface that maintains functionality in sleep modes up to and including EM2. Since in EM2 mode, only low-frequency 32.768 kHz generators are available for clocking, the LEUART interface supports only the lowest operating speed of the standard UART speeds - 9600 baud.

In addition to working with minimal power consumption, this interface provides two unusual functions for the UART. For LEUART, this can either be assigned to a start frame, before which parcels are not received, or signal frame, only for the arrival of which an interrupt is generated. In both cases, the “analysis” of input signals is performed by the controller automatically and without the participation of the core.

Since LEUART is a unit designed to reduce the energy consumption of a crystal, it is logical to demonstrate its capabilities together with the energy profiling software tool, the energy profiler utility.

The essence of the experiment

Parcels come from an external source to the serial interface - character arrays. Each character must be accepted and saved, and at the end of the reception of the string, the controller must perform some calculations. Our program is a test one, which means it is fairly simple and practically useless.
A string that comes in from a third-party device is transmitted twice per second and has the same view:
char hello[] = { 'H', 'E', 'L', 'L', 'O', ' ', 'H', 'A', 'B', 'R', '!', 0, '\r' }; 

The carriage end '\ r' character will be considered as the line end character, and the received characters are written to the rxbuf [] array. The calculations necessary for “processing” the resulting string will be reduced to the execution of an empty for (j = 0; j <1000; j ++) loop, for the execution time of which LED1 is turned on.
The purpose of the experiment will be to control and optimize the energy consumption of the crystal when performing the task of receiving and processing data.

Project setup, connection fees

In the project for the operation of low energy UART, functions from the EFM32 API are used - libraries provided by SilLabs and working “on top” of ARM CMSIS. To use them, you need to add the appropriate files to the project, you can find them in the directory ... \ SimplicityStudio \ v3 \ developer \ sdks \ efm32 \ v2 \ emlib after installing Simplicity Studio.



The example also uses the BSP (Board Support Package) package, which includes ready-made functions that simplify working with debugging boards for EFM32. These functions make it possible not to think about the topology of the board when working with modules installed on it (for example, BSP_LedInit () and BSP_LedToggle (1)). The BSP libraries are not designed to work with other cards, nor even to work with a branded card, powered by a battery, and not a debug USB. However, in a pilot project it is quite possible to afford this.

Both the EFM32 API and BSP are available for all IDEs that support EFM32 microcontrollers.

As for the LEUART connection to the transmitting device, in accordance with the LEUART software configuration (see the function initLeuart () from the listing below), it is required
a) power the board from the debug USB interface,
b) connect the D5 line and ground to the transmitter device.



The first version of the software implementation

For the clarity of the experiment, at the first iteration of writing a program, pretend to be a schoolboy and forget about the existence of interrupts. We write a program that performs an infinite loop polling serial interface:
 //.... while (1) { rx_char = LEUART_Rx(LEUART0); if(rx_char == '\r') { rxbuf[i] = rx_char; i = 0; BSP_LedToggle(1); for (j = 0; j < 1000; j++); BSP_LedToggle(1); } else { rxbuf[i] = rx_char; i++; } } } 

Full text of the program
 #include "em_chip.h" #include "em_device.h" #include "em_cmu.h" #include "em_emu.h" #include "em_leuart.h" #include "em_gpio.h" #include "bsp.h" char rx_char; int i, j; char rxbuf[13]; LEUART_Init_TypeDef LEUART0Init = { .enable = leuartEnableRx, .refFreq = 0, .baudrate = 9600, .databits = leuartDatabits8, .parity = leuartNoParity, .stopbits = leuartStopbits2, }; void initLeuart(void) { LEUART_Reset(LEUART0); LEUART_Init(LEUART0, &LEUART0Init); LEUART0->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_LOCATION_LOC0; GPIO_PinModeSet(gpioPortD, 5, gpioModeInputPull, 1); } int main(void) { CHIP_Init(); CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO); CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO); CMU_ClockEnable(cmuClock_CORELE, true); CMU_ClockEnable(cmuClock_GPIO, true); CMU_ClockEnable(cmuClock_LEUART0, true); initLeuart(); BSP_LedsInit(); while (1) { rx_char = LEUART_Rx(LEUART0); if(rx_char == '\r') { rxbuf[i] = rx_char; i = 0; BSP_LedToggle(1); for (j = 0; j < 1000; j++); BSP_LedToggle(1); } else { rxbuf[i] = rx_char; i++; } } } 


With the permission of the public, I will not give a step-by-step instruction on the creation of the project, nor explain the given code line by line. For the masses I cite a link to the instruction for creating an empty project in Simplicity IDE, from there you can use the NEXT button to blink the LED and take the next few dozen lessons.

So, to measure the power consumption of the program with an endless polling of the data reception flag, you should use the energy profiler utility, which is part of Simplicity Studio. If the project is created in Simplicity IDE, then to start profiling it is enough to find just such an icon in the top menu. If you are programming in a different environment or want to delve into the configuration settings of profiling, then you will have a direct path to the Profile Configurations settings window, available in the drop-down menu.



When configuring the configuration, the executable file and bild-a settings corresponding to the IDE used should be specified.
Many settings in Profile Configurations are also related to Code Correlation features. Code Correlation is the binding of the energy measurement results to the executable code (each point on the graph corresponds to a line in the listing). It is through this option that we are talking about profiling, and not just about measuring energy consumption. It sounds great, of course, but the Code Correlation feature is not available for the Zero Gecko series microcontrollers. In order to correlate measurements and program text, the value of the program counter must be additionally removed from the board. Such data is transmitted via the SWO line, which is not provided for on Cortex-M0 based microcontrollers. Therefore, we will be content with only the schedule of current changes being built during the execution of the program, which is also quite good.

We begin the profiling of the first version of the program.



Indeed, every 500 ms the microcontroller receives the parcel and processes it. Confirming the data from the chart, the LED on the board winks twice per second.
On average, with a constant polling of the flag, approximately 1.6 mA is consumed. This is a lot, so the program must be optimized.

The second version of the software implementation

The obvious optimization option is to use interrupts from the serial interface and put the controller to sleep while interrupting. We will execute an empty cycle and turn on LED1 in the interrupt handler.

Main () function fragment
 int main(void) { CHIP_Init(); i = 0; ... while (1) { EMU_EnterEM2(true); } } 

Interrupt Setup
 void setupLeuart(void) { LEUART_IntEnable(LEUART0, LEUART_IEN_RXDATAV); NVIC_EnableIRQ(LEUART0_IRQn); LEUART0->CTRL = LEUART_CTRL_RXDMAWU; } 

Interrupt handling
 void LEUART0_IRQHandler(void) { leuartif = LEUART_IntGet(LEUART0); LEUART_IntClear(LEUART0, leuartif); rx_char = LEUART0->RXDATA; if (rx_char == '\r') { rxbuf[i] = rx_char; i = 0; BSP_LedToggle(1); for (j=0; j<1000; j++); BSP_LedToggle(1); } else { rxbuf[i] = rx_char; i++; } } 


Full text of the program
The program almost completely repeats the example of working with LEUART, available in Simplicity Studio

 #include "em_chip.h" #include "em_device.h" #include "em_cmu.h" #include "em_emu.h" #include "em_leuart.h" #include "em_dma.h" char rx_char; int i, j; char rxbuf[12]; uint32_t leuartif; uint32_t len; LEUART_Init_TypeDef LEUART0Init = { .enable = leuartEnableRx, .refFreq = 0, .baudrate = 9600, .databits = leuartDatabits8, .parity = leuartNoParity, .stopbits = leuartStopbits2, }; void LEUART0_IRQHandler(void) { leuartif = LEUART_IntGet(LEUART0); LEUART_IntClear(LEUART0, leuartif); rx_char = LEUART0->RXDATA; if (rx_char == '\r') { rxbuf[i] = rx_char; i = 0; BSP_LedToggle(1); for (j=0; j<1000; j++); BSP_LedToggle(1); } else { rxbuf[i] = rx_char; i++; } } void initLeuart(void) { LEUART_Reset(LEUART0); LEUART_Init(LEUART0, &LEUART0Init); LEUART0->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_LOCATION_LOC0; GPIO_PinModeSet(gpioPortD, 5, gpioModeInputPull, 1); } void setupLeuart(void) { LEUART_IntEnable(LEUART0, LEUART_IEN_RXDATAV); NVIC_EnableIRQ(LEUART0_IRQn); } int main(void) { CHIP_Init(); i = 0; CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO); CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO); CMU_ClockEnable(cmuClock_CORELE, true); /* Enable CORELE clock */ CMU_ClockEnable(cmuClock_GPIO, true); /* Enable GPIO clock */ CMU_ClockEnable(cmuClock_LEUART0, true); /* Enable LEUART0 clock */ initLeuart(); setupLeuartDma(); BSP_LedsInit(); while (1) { EMU_EnterEM2(true); } } 


After changing the code, just click once on the profiler icon, the program will be compiled, the controller will be programmed, and the measurement results will be displayed on the screen. The results show that the consumption has declined many times - an average of 224 ÎĽA instead of 1.6 mA.



The microcontroller spends waiting for a parcel in the EM2 mode, this is the deepest sleep that we can afford to preserve the functionality of LEUART. Processing the results in general has nowhere to change, which means further optimization of the program is possible only for the process of receiving the parcel. Let's look at the corresponding section of the graph closer.



Upon the arrival of each character of the string {'H', 'E', 'L', 'L', 'O', '', 'H', 'A', 'B', 'R', '!', 0 , '\ r'} calls the interrupt handler, in which the newly arrived character is compared with '\ r'. Remembering that in front of us is not a normal serial interface, but LEUART, you can use not an interrupt upon the arrival of a character, but an interruption upon the arrival of SIGFRAME. Let's try.

The third version of the software implementation

Under the terms of the problem, each character of the string that has arrived should be entered into the memory of the controller. If you just change the type of interrupt, then save it would be impossible. The solution of the problem will be the use of DMA, on the zero channel of which the data will be “forwarded” to LEUART without leaving the power saving mode EM2.

Interrupt Setup
 void setupLeuartDma(void) { DMA_Init(&dmaInit); DMA_CfgChannel(DMA_CHANNEL, &chnlCfg); DMA_CfgDescr(DMA_CHANNEL, true, &descrCfg); DMA_ActivateBasic(DMA_CHANNEL, true, false, (void *) &rxbuf, (void *) &LEUART0->RXDATA, BUF_MAX-1); //-------------------------------      '\r' --------------------------------// LEUART0->SIGFRAME = '\r'; LEUART_IntEnable(LEUART0, LEUART_IEN_SIGF); //-----------------------------------------------------------------------------------------------------------// NVIC_EnableIRQ(LEUART0_IRQn); LEUART0->CTRL = LEUART_CTRL_RXDMAWU; } 

Interrupt handling
 void LEUART0_IRQHandler(void) { leuartif = LEUART_IntGet(LEUART0); LEUART_IntClear(LEUART0, leuartif); if (leuartif & LEUART_IF_SIGF) { DMA_ActivateBasic(DMA_CHANNEL, true, false, NULL, NULL, BUF_MAX-1); BSP_LedToggle(1); for (j = 0; j < 1000; j++); BSP_LedToggle(1); } } 


Full text of the program
 #include "em_chip.h" #include "em_device.h" #include "em_cmu.h" #include "em_emu.h" #include "em_leuart.h" #include "em_dma.h" #include "em_gpio.h" #define DMA_CHANNEL 0 #define BUF_MAX 1023 char rx_char; int i, j; /* DMA control block, must be aligned to 256. */ #if defined (__ICCARM__) #pragma data_alignment=256 DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2]; #elif defined (__CC_ARM) DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256))); #elif defined (__GNUC__) DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMA_CHAN_COUNT * 2] __attribute__ ((aligned(256))); #else #error Undefined toolkit, need to define alignment #endif uint32_t leuartif; uint32_t len; /* Defining the LEUART0 initialization data */ LEUART_Init_TypeDef LEUART0Init = { .enable = leuartEnableRx, /* Activate data reception on LEUn_RX pin. */ .refFreq = 0, /* Inherit the clock frequenzy from the LEUART clock source */ .baudrate = 9600, /* Baudrate = 9600 bps */ .databits = leuartDatabits8, /* Each LEUART frame containes 8 databits */ .parity = leuartNoParity, /* No parity bits in use */ .stopbits = leuartStopbits2, /* Setting the number of stop bits in a frame to 2 bitperiods */ }; /* DMA init structure */ DMA_Init_TypeDef dmaInit = { .hprot = 0, /* No descriptor protection */ .controlBlock = dmaControlBlock, /* DMA control block alligned to 256 */ }; /* Setting up channel */ DMA_CfgChannel_TypeDef chnlCfg = { .highPri = false, /* Normal priority */ .enableInt = false, /* No interupt enabled for callback functions */ .select = DMAREQ_LEUART0_RXDATAV, /* Set LEUART0 RX data avalible as source of DMA signals */ .cb = NULL, /* No callback funtion */ }; /* Setting up channel descriptor */ DMA_CfgDescr_TypeDef descrCfg = { .dstInc = dmaDataInc1, /* Increment destination address by one byte */ .srcInc = dmaDataIncNone, /* Do no increment source address */ .size = dmaDataSize1, /* Data size is one byte */ .arbRate = dmaArbitrate1, /* Rearbitrate for each byte recieved*/ .hprot = 0, /* No read/write source protection */ }; void LEUART0_IRQHandler(void) { leuartif = LEUART_IntGet(LEUART0); LEUART_IntClear(LEUART0, leuartif); if (leuartif & LEUART_IF_SIGF) { DMA_ActivateBasic(DMA_CHANNEL, true, false, NULL, NULL, BUF_MAX-1); BSP_LedToggle(1); for (j = 0; j < 1000; j++); BSP_LedToggle(1); } } void initLeuart(void) { LEUART_Reset(LEUART0); LEUART_Init(LEUART0, &LEUART0Init); LEUART0->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_LOCATION_LOC0; GPIO_PinModeSet(gpioPortD, 5, gpioModeInputPull, 1); } void setupLeuartDma(void) { DMA_Init(&dmaInit); DMA_CfgChannel(DMA_CHANNEL, &chnlCfg); DMA_CfgDescr(DMA_CHANNEL, true, &descrCfg); DMA_ActivateBasic(DMA_CHANNEL, true, false, (void *) &rxbuf, (void *) &LEUART0->RXDATA, BUF_MAX-1); LEUART0->SIGFRAME = '\r'; LEUART_IntEnable(LEUART0, LEUART_IEN_SIGF); NVIC_EnableIRQ(LEUART0_IRQn); LEUART0->CTRL = LEUART_CTRL_RXDMAWU; } int main(void) { CHIP_Init(); i = 0; CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO); CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO); CMU_ClockEnable(cmuClock_CORELE, true); CMU_ClockEnable(cmuClock_DMA, true); CMU_ClockEnable(cmuClock_GPIO, true); CMU_ClockEnable(cmuClock_LEUART0, true); initLeuart(); setupLeuartDma(); BSP_LedsInit(); while (1) { EMU_EnterEM2(true); } } 



We run the profiling for the third time and we get evidence that the optimization made makes sense - the consumption has decreased from 224 to 139 ÎĽA.



The “teeth” disappeared, corresponding to the interrupt handling for each incoming character. Due to this, the power consumption for data reception / processing, and the average value have decreased significantly.

I would not like to go into the comparison of specific numbers (the line could, for example, be longer, and the parcels more often), but I think that the principle of reducing consumption using low energy UART and the energy profiler is described quite clearly.

Example # 3 Work with PCNT hardware pulse counter and crystal configurator



Consider another interesting development tool, configurator for peripherals and I / O lines. Selecting the corresponding item of the main menu of Simplicity Studio and specifying the part number to use, you can start creating a new project in the graphic environment of the controller settings.

For the EFM32ZG110F32 microcontroller (yes, still $ 0.96 apiece), this interface is available to the user:

I / O line settings window



Peripherals Settings Window



The general principle of operation in the Configurator is as follows: the required peripherals are selected, the operation mode is configured for each block, then the I / O lines necessary for the blocks are assigned, the configuration is set for each line. After configuration, the project generation for the development environment is started.
The configurator allows you to simplify the initial stage of programming - instead of squeezing the peripheral settings from the documentation, a graphical interface is used. In addition, this utility allows you to quickly assess the capabilities of the selected crystal and make a simple trial project. Such a configurator is the majority of manufacturers of microcontrollers.

With the use of the configurator, we will get acquainted with a 16-bit pulse counter. Like LEUART, this module is rarely found on microcontrollers, and, like LEUART, a pulse counter reduces the power consumption of a device.

So, in the configuration menu of the EFM32ZG110F32 microcontroller, we tick the PCNT0 and look at the available settings.



The module can be configured to count the number of pulses arriving at one of the crystal ports; in this case, an interrupt is generated when a specified number of pulses are reached. Another variant of the module operation is the quadrature encoder mode with an interruption by changing the count direction (clockwise / counterclockwise).
The PCNT counter can use one or two input signals. In the “Single input, LFACLK oversampling” and “Single input, externally clocked” pulse counting modes, only the S0 line is used, and the signal to S1 is ignored. In the “Quadrature decoder mode, externally clocked” mode both input signals are used.

The PCNT counter is available in sleep modes up to EM3, however, in the “Single input, LFACLK oversampling” pulse counting mode, an internal rather than an external clock source is used, so it is possible to use power consumption modes no lower than EM2. Operation of the unit in EM3 mode is also not possible if the Peripheral Reflex System channels are not used as PCNT input inputs, not the microcontroller I / O lines. On the other hand, EM2 is the power consumption in microamps units, which is quite acceptable for an encoder.

Let's set up through the configurator the settings of the simplest PCNT mode. Let the fifth pulse be detected on one of the GPIO lines.
We set the operation mode to “Single input, LFACLK oversampling”, the Initial top value is set to “5”, leave the account settings (Count the edges of the positive edges) and the count direction Count up) by default, enable the filter out filter out pulses shorter then 5 clockcycles ”to protect against chatter. Input channel settings remain the default because The second channel in the Single input mode is ignored, and the first uses the controller's foot, and not the PRS channel. The remaining properties of the Pulse Counter menu refer to the quadrature encoder mode, so we don’t look at them at all.



Having seen our settings, the configurator rightly notes that once the pulses arriving on one of the I / O lines are counted, this line must be selected and configured.



By clicking on the error message, go to the I / O line settings window, where two locations are available for the S0IN line:



Suppose that the second location, i.e. line PC0, suits us better. Again we look into the error window.



And, again agreeing with the configurator, we change the mode of operation of the controller leg from Disabled to Input.



Now you can generate the source code for a given configuration of the microcontroller EFM32ZG110F32. In the right-click menu of the mouse, we find the Generate Source command and get the finished project. The project contains the initialization of the crystal - setting the clocking, pulse counter and GPIO, as well as an empty while (1) loop in the function main ().

 extern void enter_DefaultMode_from_RESET(void) { CMU_enter_DefaultMode_from_RESET(); PCNT0_enter_DefaultMode_from_RESET(); PORTIO_enter_DefaultMode_from_RESET(); } extern void CMU_enter_DefaultMode_from_RESET(void) { CMU_OscillatorEnable(cmuOsc_LFRCO, true, true); CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO); CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO); CMU_ClockEnable(cmuClock_CORELE, true); CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO); CMU_ClockEnable(cmuClock_PCNT0, true); CMU_ClockEnable(cmuClock_GPIO, true); } extern void PCNT0_enter_DefaultMode_from_RESET(void) { PCNT_Init_TypeDef init = PCNT_INIT_DEFAULT; init.counter = 0; init.top = 5; init.negEdge = 0; init.countDown = 0; init.filter = 1; init.hyst = 0; init.s1CntDir = 0; init.cntEvent = pcntCntEventUp; init.auxCntEvent = pcntCntEventNone; init.s0PRS = pcntPRSCh0; init.s1PRS = pcntPRSCh0; PCNT_Init(PCNT0, &init); PCNT_Enable(PCNT0, pcntModeOvsSingle); } extern void PORTIO_enter_DefaultMode_from_RESET(void) { /* Pin PC0 is configured to Input enabled */ GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | GPIO_P_MODEL_MODE0_INPUT; /* Module PCNT0 is configured to location 2 */ PCNT0->ROUTE = (PCNT0->ROUTE & ~_PCNT_ROUTE_LOCATION_MASK) | PCNT_ROUTE_LOCATION_LOC2; } 


Full text of the program
Main.c file
 /**************************************************************************//** * @file * @brief Empty Project * @author Energy Micro AS * @version 3.20.2 ****************************************************************************** * @section License * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> ******************************************************************************* * * This file is licensed under the Silicon Labs Software License Agreement. See * "http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt" * for details. Before using this software for any purpose, you must agree to the * terms of that agreement. * ******************************************************************************/ #include "em_device.h" #include "em_chip.h" /**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { /* Chip errata */ CHIP_Init(); /* Infinite loop */ while (1) { } } 


InitDevice.c file

 //========================================================= // src/InitDevice.c: generated by Hardware Configurator // // This file will be regenerated when saving a document. // leave the sections inside the "$[...]" comment tags alone // or they will be overwritten! //========================================================= // USER INCLUDES #include "InitDevice.h" // USER PROTOTYPES // USER FUNCTIONS // $[Library includes] #include "em_system.h" #include "em_emu.h" #include "em_cmu.h" #include "em_device.h" #include "em_chip.h" #include "em_pcnt.h" // [Library includes]$ //============================================================================== // enter_DefaultMode_from_RESET //============================================================================== extern void enter_DefaultMode_from_RESET(void) { // $[Config Calls] CMU_enter_DefaultMode_from_RESET(); PCNT0_enter_DefaultMode_from_RESET(); PORTIO_enter_DefaultMode_from_RESET(); // [Config Calls]$ } //================================================================================ // HFXO_enter_DefaultMode_from_RESET //================================================================================ extern void HFXO_enter_DefaultMode_from_RESET(void) { // $[HFXO] // [HFXO]$ } //================================================================================ // LFXO_enter_DefaultMode_from_RESET //================================================================================ extern void LFXO_enter_DefaultMode_from_RESET(void) { // $[Use oscillator source] // [Use oscillator source]$ // $[LFXO Boost Percent] // [LFXO Boost Percent]$ // $[REDLFXO Boost] // [REDLFXO Boost]$ } //================================================================================ // CMU_enter_DefaultMode_from_RESET //================================================================================ extern void CMU_enter_DefaultMode_from_RESET(void) { // $[LFXO enable] // [LFXO enable]$ // $[HFXO enable] // [HFXO enable]$ // $[LFACLK Setup] /* Enable LFRCO oscillator */ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true); /* Select LFRCO as clock source for LFACLK */ CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO); // [LFACLK Setup]$ // $[High Frequency Clock select] /* Using HFRCO at 14MHz as high frequency clock, HFCLK */ CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO); // [High Frequency Clock select]$ // $[LF clock tree setup] /* Enable LF clocks */ CMU_ClockEnable(cmuClock_CORELE, true); CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO); // [LF clock tree setup]$ // $[Peripheral Clock enables] /* Enable clock for PCNT0 */ CMU_ClockEnable(cmuClock_PCNT0, true); /* Enable clock for GPIO by default */ CMU_ClockEnable(cmuClock_GPIO, true); // [Peripheral Clock enables]$ } //================================================================================ // ADC0_enter_DefaultMode_from_RESET //================================================================================ extern void ADC0_enter_DefaultMode_from_RESET(void) { // $[ADC_Init] // [ADC_Init]$ // $[ADC_InitSingle] // [ADC_InitSingle]$ // $[ADC_InitScan] // [ADC_InitScan]$ } //================================================================================ // ACMP0_enter_DefaultMode_from_RESET //================================================================================ extern void ACMP0_enter_DefaultMode_from_RESET(void) { // $[ACMP Initialization] // [ACMP Initialization]$ // $[ACMP Channel config] // [ACMP Channel config]$ } //================================================================================ // IDAC0_enter_DefaultMode_from_RESET //================================================================================ extern void IDAC0_enter_DefaultMode_from_RESET(void) { // $[IDAC Initialization] // [IDAC Initialization]$ // $[IDAC optional configurations] // [IDAC optional configurations]$ // $[IDAC enable] // [IDAC enable]$ } //================================================================================ // RTC_enter_DefaultMode_from_RESET //================================================================================ extern void RTC_enter_DefaultMode_from_RESET(void) { // $[RTC_Init] // [RTC_Init]$ } //================================================================================ // USART1_enter_DefaultMode_from_RESET //================================================================================ extern void USART1_enter_DefaultMode_from_RESET(void) { // $[USART_InitAsync] // [USART_InitAsync]$ // $[USART_InitSync] // [USART_InitSync]$ // $[USART_InitPrsTrigger] // [USART_InitPrsTrigger]$ } //================================================================================ // LEUART0_enter_DefaultMode_from_RESET //================================================================================ extern void LEUART0_enter_DefaultMode_from_RESET(void) { // $[LEUART0 initialization] // [LEUART0 initialization]$ } //================================================================================ // VCMP_enter_DefaultMode_from_RESET //================================================================================ extern void VCMP_enter_DefaultMode_from_RESET(void) { // $[VCMP_Init] // [VCMP_Init]$ } //================================================================================ // WDOG_enter_DefaultMode_from_RESET //================================================================================ extern void WDOG_enter_DefaultMode_from_RESET(void) { // $[CMU_ClockEnable] // [CMU_ClockEnable]$ // $[CMU_OscillatorEnable] // [CMU_OscillatorEnable]$ // $[WDOG_Init] // [WDOG_Init]$ } //================================================================================ // I2C0_enter_DefaultMode_from_RESET //================================================================================ extern void I2C0_enter_DefaultMode_from_RESET(void) { // $[I2C0 initialization] // [I2C0 initialization]$ } //================================================================================ // TIMER0_enter_DefaultMode_from_RESET //================================================================================ extern void TIMER0_enter_DefaultMode_from_RESET(void) { // $[TIMER0 initialization] // [TIMER0 initialization]$ // $[TIMER0 CC0 init] // [TIMER0 CC0 init]$ // $[TIMER0 CC1 init] // [TIMER0 CC1 init]$ // $[TIMER0 CC2 init] // [TIMER0 CC2 init]$ } //================================================================================ // TIMER1_enter_DefaultMode_from_RESET //================================================================================ extern void TIMER1_enter_DefaultMode_from_RESET(void) { // $[TIMER1 initialization] // [TIMER1 initialization]$ // $[TIMER1 CC0 init] // [TIMER1 CC0 init]$ // $[TIMER1 CC1 init] // [TIMER1 CC1 init]$ // $[TIMER1 CC2 init] // [TIMER1 CC2 init]$ } //================================================================================ // PCNT0_enter_DefaultMode_from_RESET //================================================================================ extern void PCNT0_enter_DefaultMode_from_RESET(void) { // $[PCNT0 initialization] PCNT_Init_TypeDef init = PCNT_INIT_DEFAULT; init.counter = 0; init.top = 5; init.negEdge = 0; init.countDown = 0; init.filter = 1; init.hyst = 0; init.s1CntDir = 0; init.cntEvent = pcntCntEventUp; init.auxCntEvent = pcntCntEventNone; init.s0PRS = pcntPRSCh0; init.s1PRS = pcntPRSCh0; PCNT_Init(PCNT0, &init); /* Activating PCNT0 */ PCNT_Enable(PCNT0, pcntModeOvsSingle); // [PCNT0 initialization]$ } //================================================================================ // PRS_enter_DefaultMode_from_RESET //================================================================================ extern void PRS_enter_DefaultMode_from_RESET(void) { // $[PRS initialization] // [PRS initialization]$ } extern void PORTIO_enter_DefaultMode_from_RESET(void) { // $[Port A Configuration] // [Port A Configuration]$ // $[Port B Configuration] // [Port B Configuration]$ // $[Port C Configuration] /* Pin PC0 is configured to Input enabled */ GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | GPIO_P_MODEL_MODE0_INPUT; // [Port C Configuration]$ // $[Port D Configuration] // [Port D Configuration]$ // $[Port E Configuration] // [Port E Configuration]$ // $[Port F Configuration] // [Port F Configuration]$ // $[Route Configuration] /* Module PCNT0 is configured to location 2 */ PCNT0->ROUTE = (PCNT0->ROUTE & ~_PCNT_ROUTE_LOCATION_MASK) | PCNT_ROUTE_LOCATION_LOC2; // [Route Configuration]$ } 


. , , .

EFM32ZG-STK3200.

#4 -



, J-Link, EFM32ZG-STK3200 , «» EFM32. , EFM32ZG-STK3200 energy profiler.
EFM32ZG-STK3200 .

1.

EFM32ZG-STK3200 USB , Simplicity Studio Kit Manager. Debug Mode MCU Out.



2.

EFM32ZG-STK3200 Cortex- 20- SWD (Serial Wire Debug). , 20 .



SWO . EFM32 Zero Gecko, Cortex-M0/-M0+, SWO , EFM32ZG-STK3200 J-Link Cortex-M3 , SWO .

Reset , , , highly recommended. , , .

, VMCU. VMCU , energy profiler , .

3. IDE

Simplicity IDE EFM32ZG-STK3200 Debug Out . Keil IAR J-Link, AN0043 — EFM32 Debug and Trace .

#5 EFM32 mbed



EFM32 Zero Gecko mbed ARM.
mbed — , IoT-. mbed OS Cortex-M, -IDE, (, , , ..), . .
mbed mbed EFM32 Zero Gecko.

SiLabs — , mbed. , EFM32ZG , , -. And this will do.

(. Debug Mode: MCU #4) USB-. ( DBG), . , — : mbed mbed. mbed , -- . Kit Manager Simplicity Studio. , Kit Manager . .

mbed . developer.mbed.org , Platforms EFM32ZG-STK3200.



mbed - . EFM32ZG-STK3200, IDE.



. : : .


, . .


. EFM32, mbed, Mass Storage Device.



developer.mbed.org STK3200, .



, mbed . , mbed . .

mbed . sleep(), mbed. EFM32 , mbed sleep API , ARM mbed.

 #include "mbed.h" DigitalOut myled(LED1); LowPowerTicker toggleTicker; void ledToggler(void) { myled = !myled; } int main() { toggleTicker.attach(&ledToggler, 0.2f); while(1) { sleep(); } } 


Conclusion



Thanks for attention. , EFM32ZG110F32 EFM32 . , email, .

Source: https://habr.com/ru/post/277899/


All Articles