C. How can I prevent this issue from affecting my application?
D. Are there plans to fix this issue?
Answers:
A.
Erratum RMU_E103 describes an issue with certain Series 0 EFM32 devices. Affected parts see a gap in the coverage of the brown-out and power-on reset sources around 1.3V . The exact gap in reset coverage will be part specific if present at all. If an affected device is operating in this problematic VDD range, the device will attempt to start up while well below the tested supply voltage for the microcontroller.
The device takes a short amount of time to start up. For a typical part at normal voltages this is 163 µS. If the startup succeeds, the device will then attempt to execute code, but may not be able to do so at low voltage. At this low voltage neither a successful startup or successful code execution is guaranteed.
Note that during fast voltage ramps, e.g. power-on and power down events, VDD will not be at a problematic voltage long enough for the device to start up. However, if VDD is held at around 1.3V for a sufficient duration, the device may enter this undefined state where code is being executed below tested voltages.
The workaround to this issue is to assert a pin reset during the low VDD event. If a pin reset is asserted, the device cannot attempt to start up. The reset pin should be driven low prior to VDD falling below the BOD reset threshold.
B.
RMU_E103 is an erratum that effects some devices from the following EFM32 Series 0 products:
EFM32 Zero Gecko
EFM32 Happy Gecko
EFM32 Wonder Gecko
EFM32 Leopard Gecko
EFM32 Tiny Gecko (Series 0 only)
EZR32 Happy Gecko
EZR32 Wonder Gecko
EZR32 Leopard Gecko
This erratum does not affect EFM32 Gecko, Giant gecko, or any EFM32 Series 1 devices.
C.
Steps can be taken to both detect if RMU_E103 is occurring on a specific device, and to prevent code from executing at low voltage.
To detect a gap in reset source coverage, Measure the current consumption of the device while gradually lowering VDD. If the device attempts to start up at low voltage, current consumption will increase. The diagram below shows an example VDD waveform that can test for code execution at low voltage and the corresponding spike in current consumption. Note that the current and voltage values are approximate and will vary across parts, applications, and environments.
Figure 1. VDD Test for RMU_E103 Current Consumption
To avoid code execution at low voltage, avoid slow VDD ramps during normal operation. If the application is likely to experience a slow VDD ramp or see low supply voltage for any significant duration of time, use an external device or user input to assert a pin reset at some VDD level > 1.96V (with sufficient time to engage the internal reset before VDD reaches 1.96V).
D.
A production screen has been implemented for EFM32 Tiny Gecko that catches devices susceptible to this condition and is implemented on material with date code 1909 and later. Silicon fixes are planned for the remaining devices.
C. How can I prevent this issue from affecting my application?
D. Are there plans to fix this issue?
Answers:
A.
Erratum RMU_E102 describes an issue with certain Series 0 EFM32 devices. Affected parts may see voltage regulator failure when subjected to the following scenario:
VDD begins to fall due to some external event
VDD and Regulator output (DECOUPLE) voltage decay to 0.8-1.2V
Power supply to VDD is restored and VDD returns to a nominal value prior to VDD and DECOUPLE reaching < 0.8V
In this type of sequence mentioned above , the voltage regulator may fail to re-initialize. If this occurs, the DECOUPLE pin will continue to decay to 0V, even after VDD has recovered. In this state, the core logic is not powered, and the device will be unable to execute code or respond to a pin reset. An affected device will successfully recover from this state if power cycled.
Additionally, if a pin reset is applied prior to the Brown out detector (BOD) asserting reset, the regulator will always re-initialize successfully. The BOD threshold varies between 1.74-1.96V, so a pin reset should be asserted before VDD drops below 1.96V. The pin-reset should be held low until VDD is >1.98V, which is the maximum power-on reset threshold.
The diagrams below demonstrate an example VDD waveform that can cause the regulator initialization to fail.
Figure 1. VDD Decay and Recovery
This figure shows the proper recovery sequence, or what will happen to a working device (not affected by RMU_E102) when VDD falls to 0.9V. Here, the regulator restarts after VDD is restored, and the DECOUPLE voltage returns to 1.8V.
Figure 2. VDD Decay and DECOUPLE failure
This figure shows the failure mode for a device affected by RMU_E102 when VDD falls to 0.9V. As you can see the regulator fails to re-initialize properly, and the DECOUPLE voltage continues to fall until reaching 0V. At this point a power-on reset must be performed to recover the device.
As mentioned above, there are two workarounds to the issue.
For a device that is already in lock-up, perform a power cycle to recover to a normal state. To do this VDD must be driven to 0V before powering back on.
For a device that may experience a drop in VDD to 0.8-1.2V, use an external device or user input to assert a pin reset at some VDD level > 1.96V (with sufficient time to engage the internal reset before VDD reaches 1.96V). Additionally, the reset should be held low until power is reconnected and VDD is greater than 1.98V.
B.
RMU_E102 is an erratum that effects some devices from the following EFM32 Series 0 products:
EFM32 Zero Gecko
EFM32 Happy Gecko
EFM32 Wonder Gecko
EFM32 Leopard Gecko
EFM32 Tiny Gecko (Series 0 only)
EZR32 Happy Gecko
EZR32 Wonder Gecko
EZR32 Leopard Gecko
This erratum does not affect EFM32 Gecko, Giant Gecko, or any EFM32 Series 1 devices.
C.
To avoid issues caused by RMU_E102, the following precautions should be taken.
Avoid and check for intermittent battery or power supply connections to VDD. The issue was originally discovered in situations where a loose battery connection during assembly caused VDD to repeatedly drop to ~.9V and then recover to a nominal value. This represents a worst-case scenario for inducing RMU_E102, as multiple VDD disconnections occurred within a very short time frame.
If your application is likely to experience frequent disconnects from the power supply, ensure that the reset pin is driven low prior to disconnecting.
D.
A production screen has been implemented for EFM32 Tiny Gecko that catches devices susceptible to this condition and is implemented on material with date code 1909 and later. Silicon fixes are planned for the remaining devices.
I'm trying to output two sine waves to the two VDAC channels on the EFR32BG13 by reading these values from a table and writing them to the VDAC_COMBDATA register with LDMA (later I'm going to output data in the same fashion as it is received via BLE).
I setup two 16-bit buffers with the data and initialize the LDMA as follows:
#define BUFFER_SIZE 4
uint16_t pingBuffer[BUFFER_SIZE];
uint16_t pongBuffer[BUFFER_SIZE];
// Ping-pong transfer count
uint32_t ppCount;
// Descriptor linked list for LDMA transfers
LDMA_Descriptor_t descLink[2];
void initLdmaPingPong(void)
{
CMU_ClockEnable(cmuClock_LDMA, true);
// Basic LDMA configuration
LDMA_Init_t ldmaInit = LDMA_INIT_DEFAULT;
LDMA_Init(&ldmaInit);
// Configure LDMA transfer type
cfg = (LDMA_TransferCfg_t)LDMA_TRANSFER_CFG_PERIPHERAL(ldmaPeripheralSignal_VDAC0_CH0);
// Use LINK descriptor macros for ping-pong transfers
LDMA_Descriptor_t xfer[] =
{
LDMA_DESCRIPTOR_LINKREL_M2P_BYTE(
&pingBuffer, // source
&(VDAC0->COMBDATA), // destination
BUFFER_SIZE, // data transfer size
1), // link relative offset (links to next)
LDMA_DESCRIPTOR_LINKREL_M2P_BYTE(
&pongBuffer, // source
&(VDAC0->COMBDATA), // destination
BUFFER_SIZE, // data transfer size
-1) // link relative offset(links to previous)
};
descLink[0] = xfer[0];
descLink[1] = xfer[1];
descLink[0].xfer.ignoreSrec = true; // ignores single requests to reduce energy usage
descLink[0].xfer.size = ldmaCtrlSizeHalf; // transfers half words instead of bytes
descLink[1].xfer.ignoreSrec = true; // ignores single requests to reduce energy usage
descLink[1].xfer.size = ldmaCtrlSizeHalf; // transfers half words instead of bytes
LDMA_IntEnable(LDMA_IF_DONE_DEFAULT);
// Start Ping-Pong transfer
ppCount = 0;
LDMA_StartTransfer(LDMA_CHANNEL, (void*)&cfg, (void*)&descLink);
NVIC_ClearPendingIRQ(LDMA_IRQn);
NVIC_EnableIRQ(LDMA_IRQn);
}
A TIMER triggers the VDAC output via the PRS, and I fill the buffers accordingly when the LDMA triggers its DONE interrupt.
The problem I have is that I only get the correct output on channel 0. If I transfer longwords using the LDMA, then I get a signal from both outputs, but the output is not correct, e.g. every fourth ping-pong transfer fails, and I get 0V output for this period.
What is the correct structure to write to the COMBDATA register? How do I manage to accomplish this with a ping-pong buffer?
Our user's setup of the LDMA here is mostly correct except for one major flaw:
descLink1[0].xfer.ignoreSrec = true; // ignores single requests to reduce energy usage
descLink1[0].xfer.size = ldmaCtrlSizeHalf; // transfers half words instead of bytes
descLink1[1].xfer.ignoreSrec = true; // ignores single requests to reduce energy usage
descLink1[1].xfer.size = ldmaCtrlSizeHalf; // transfers half words instead of bytes
While this looks correct, in theory, the problem is with the attempt to use halfwords for the transfer size. While there is no issue itself with the LDMA performing a halfword read or write, it cannot do so when the target register is a memory-mapped peripheral. All write accesses to peripheral registers must be longword writes. In the case of the COMBDATA register, this actually makes perfect sense when you consider that its sole purpose is to update both VDAC output channels simultaneously.
So, in the customer's case, the solution is fairly simple. Instead of maintaining two ping-pong buffer arrays of type uint16_t, the data to be buffered needs to be stored to permit the two 16-bit output values to be read as 32 bits that are written together to the COMBDATA register. This could be done by simple ordering the data so that the 0th entry in the buffer is the first channel 1 output value (VDAC_COMBDATA_CH1DATA), the 1st entry is the first channel 0 output value (VDAC_COMBDATA_CH0DATA), the 2nd entry is the second channel 1 output value, the 3rd entry is the second channel 0 output value, etc. The same thing could be done with a typedef struct that has as its two components variables for the channel 1 and channel 0 output values.
Having made this change, the LDMA descriptors would be modified for 32-bit transfers:
descLink1[0] = xfer[0];
descLink1[1] = xfer[1];
descLink1[0].xfer.ignoreSrec = true; // ignores single requests to reduce energy usage
descLink1[0].xfer.size = ldmaCtrlSizeWord; // transfers words instead of bytes
descLink1[1].xfer.ignoreSrec = true; // ignores single requests to reduce energy usage
descLink1[1].xfer.size = ldmaCtrlSizeWord; // transfers words instead of bytes
If there's a need to generate a waveform on one output, then have it remain unchanged while the other channel is updated, this could be done with the original code above with the proviso that the destination for each descriptor would be &(VDAC0->CH0DATA) or &(VDAC0->CH1DATA) as needed.
NOTE: While this discussion involves the VDAC on Series 1 EFM32 and EFR32 devices, it applies identically to the DAC on Series 0 EFM32 and EZR32 devices. The requirement for aligned longword accesses to peripheral registers is universal across all EFM32, EFR32, and EZR32 devices.
The first line specifies that the address of the following variable should be 0x0FE04000 + (127 << 2 ) = 0x0FE041FC. LOCKBITS_BASE is #defined in the CMSIS Cortex-M Peripheral Access Layer Header File for the device in question and is 0x0FE04000 for all current EFM32, EFR32, and EZR32 devices.
Naturally, the constant debug_lock_word sets the DLW to 0x0 (at the previously specified address), but what does the __root modifier do? As explained in the following IAR Technical Note...
__root prevents the linker from removing a variable or function if it is not referred to in the main() call-tree or in any interrupt call-tree. Short of perhaps checking the state of the debug_lock_word in firmware to enable/disable debugging features, there would usually be no reason for it to be referenced in main() or elsewhere, thus the need to prevent the linker from removing it.
Obviously, this same technique can be used for any of the other words in the lock bits page. For example, to have pin resets treated as hard instead of soft resets, it's necessary to clear bit 2 of lock bits page word 122, which is configuration word 0 (CLW0), and is done with (bit 1 of CLW0 enables the bootloader and remains set in this particular example):
Locations in user data space can be programmed with constant data in the same way. For example, a product and manufacturer name could be stored as follows:
A curious user might ask "How exactly do I know this works? The .hex file format is rather cryptic looking to the untrained eye. Is there a way to parse this .hex file output from the build process and verify the expected constants are there?"
Various binary tools can be used to dump and otherwise convert .hex files, but the output from the attached hexinfo program (attached to this article for Windows machines after compiling from the sources at https://github.com/bradgrantham/hex2bin) does the job conveniently enough:
Each contiguous region in the hex file can be associated with a section of the compiled binary data. The largest is, of course, the program code itself, while the three smaller regions correspond to the product_name, manufacturer_name, and debug_lock_word constant definitions at the addresses specified by the location #pragmas that precede them.
I've run into an interesting problem: If I attempt to read the pulse counter PCNTn_CNT register shortly after the edge which increments the counter, say in an interrupt handler triggered by the rising or falling edge of the GPIO pin used, the count value does not reflect the newly captured edge.
However, if I set a break point in my interrupt handler and step through the call to the PCNT_CounterGet() function, the value returned is correct! What's happening here?
This is a perfect example of the clock domain boundary crossing problem, which is what happens when a CPU running from one clock source reads a register clocked by another, asynchronous source. On EFM32 Series 0 devices, the CPU runs off the HFCORECLK while the pulse counter runs from either the LFACLK or the edges that appear on the PCNTn_S0 pin. These clocks are, of course, asynchronous, and the pulse counter runs at what is generally a much lower frequency than the HFCORECLK, so there is a sizable delay between when the PCNTn_CNT register gets updated after an edge and when the CPU core can actually see the new value.
Reading from and writing to asynchronous registers, i.e. those associated with the low-energy peripherals, is documented in section 5.2.4 Access to Low Energy Peripherals (Asynchronous Registers) of each device's reference manual, including use of the peripheral's FREEZE register, if present. Unfortunately, in the case of the pulse counter, the FREEZE register doesn't provide any help.
What really seems to be needed is some kind of flag bit indicating that an update to the CNT register is in progress. Of course, the logic driving this bit would have to use the same clock as the counter, creating a kind of Catch-22 situation.
Ultimately, the nature of this problem is that it takes some number of PCNTn_CLK clock ticks relative to HFCORECLK ticks to guarantee that the value read from the CNT register is up-to-date. Consequently, if there's no way to enforce this synchronization on the read side of the equation, can it be done by proxy using a write?
The answer is yes, thanks to the PCNTn_SYNCBUSY register, which indicates when writes to the TOPB, CMD, and CTRL registers are in progress. Given that SYNCBUSY effectively reflects the propagation of data from the HFCORECLK domain into the PCNTn_CLK domain, it's safe to assume that a synchronized write issued after the edge that triggers the GPIO interrupt in the customer's example above, will guarantee that the value read from PCNTn_CNT includes this edge.
Of course, to do this, it's necessary to know the correct register and the value to write — really rewrite — to it such that the pulse counter keeps running as configured. TOPB looks to be the best option because the value written to it is unlikely to change (or at least be changed infrequently) after initialization. So, given this, here's what the interrupt handler in question would now look like:
void GPIO_ODD_IRQHandler(void)
{
/*
* Rewrite TOP to reset value; this will account for the time
* needed for the read of CNT to reflect the most recent edge.
*/
PCNT_TopSet(PCNT1, _PCNT_TOP_RESETVALUE);
// Update number of pulses on LCD after each button push
SegmentLCD_Number(PCNT_CounterGet(PCNT1));
// Clear flag for PB9 interrupt
GPIO_IntClear(0x0200);
}
For convenience, TOP (via TOPB) is rewritten to its reset value. If it's not possible to know the specific value of TOP when the interrupt handler is running, simply reading TOP and rewriting that value via TOPB would also work:
/*
* Get current value of TOP and rewrite it to account for the time
* needed for the read of CNT to reflect the most recent edge.
*/
PCNT_TopSet(PCNT1, PCNT_TopGet(PCNT1));
Attached to this article is an example for the STK3800 Wonder Gecko Starter Kit (STK) — porting it to the STK3700 Giant Gecko or STK3600 Leopard Gecko boards would be trivial — that illustrates the use of SYNCBUSY (via the emlib PCNT_TopSet() function) to provide the synchronization needed to read CNT and have it reflect the most recent edge captured.
When the PCNT_TopSet() call is commented out of the interrupt handler, the first push of button 0 on the STK, while engaging the GPIO_ODD_IRQHandler(), will not be reflected in the count displayed on the LCD. However, setting a breakpoint in and then single-stepping through the interrupt handler allows enough LFACLK edges to propagate through the pulse counter so that the most recent edge increments the CNT register in time for the display to be updated.
To import the demo project Simplicity Studio...
In the IDE, go to the File -> Import...
Click the "More Import Options..." link at the bottom of the window
Expand the General folder and select "Existing Projects into Workspace"
Click the radio button next to "Select archive file:"
Click the Browse... button next to the active file selection field and choose the STK3800_pcnt_count.zip file with the project to import.
The Projects: dialog box, should have the selected project with a check mark next to it.
I ran into a discrepancy trying to get the pulse counter (PCNT2, specifically) up and running on an EFM32 Wonder Gecko device and just wanted to confirm that what I am seeing is correct. The reference manual section with the register description (section 24.5) shows the TOP and CNT fields as 16 bits. When I try to set the TOP register (through the TOPB register, e.g. PCNT2->TOPB = 0x1FF) only the lower byte is set. AN0024 says the pulse counter incorporates an 8-bit counter which is consistent with what I saw.
Can you please confirm that the register description in the reference manual is incorrect?
Actually, the Reference Manual description...
...is correct! What matters is which pulse counter you want to use. On any EFM32 device with multiple instances of a peripheral (the USART is another such example), it's critical to refer to the datasheet to see how that peripheral has been configured on the device in question.
In the case of Wonder Gecko, as the datasheet shows and to appropriate a line from Goerge Orwell's Animal Farm, "All pulse counters are equal, but some pulse counters are more equal than others."
So, in this case, the customer absolutely did observe the correct behavior because PCNT2 (and, likewise, PCNT1) are 8-bit instantiations of the peripheral. If, instead, the customer had tried PCNT0, it would've behaved as he initially expected when attempting to write a 16-bit value to the TOPB register.
Note also that emlib is aware of the width associated with each pulse counter instantiation. Attempts to write 16-bit values into the CNT or TOPB registers of PCNT1 or PCNT2 using the relevant emlib functions will generate an assertion upon execution when code is built using the debug configuration in Simplicity Studio. In this particular case, the customer wrote directly to the TOPB register, thus bypassing the error checking emlib would otherwise provide.
By convention, on all EFM32 Series 0 devices — except for the original Gecko, which has only a single 8-bit pulse counter — PCNT0 is 16 bits and PCNT1 and PCNT2, if present, are 8 bits.
The ADC circuit is a 300-800 ohm resistor in series with a 2 pF capacitor, plus ESD protection diodes. There is no loading, and the maximum leakage on the input pin is 50 nA. This applies to series 0 EFM32 parts: Gecko, Giant Gecko, Tiny Gecko, Leopard Gecko, Wonder Gecko, Zero Gecko, and Happy Gecko. The equivalent diagrams in single-ended and differential mode are shown below:
32-bit Knowledge Base
RMU_E103 POR/BOD Reset Issue
Questions:
A. What is Errata RMU_E103
B. What devices are affected?
C. How can I prevent this issue from affecting my application?
D. Are there plans to fix this issue?
Answers:
A.
Erratum RMU_E103 describes an issue with certain Series 0 EFM32 devices. Affected parts see a gap in the coverage of the brown-out and power-on reset sources around 1.3V . The exact gap in reset coverage will be part specific if present at all. If an affected device is operating in this problematic VDD range, the device will attempt to start up while well below the tested supply voltage for the microcontroller.
The device takes a short amount of time to start up. For a typical part at normal voltages this is 163 µS. If the startup succeeds, the device will then attempt to execute code, but may not be able to do so at low voltage. At this low voltage neither a successful startup or successful code execution is guaranteed.
Note that during fast voltage ramps, e.g. power-on and power down events, VDD will not be at a problematic voltage long enough for the device to start up. However, if VDD is held at around 1.3V for a sufficient duration, the device may enter this undefined state where code is being executed below tested voltages.
The workaround to this issue is to assert a pin reset during the low VDD event. If a pin reset is asserted, the device cannot attempt to start up. The reset pin should be driven low prior to VDD falling below the BOD reset threshold.
B.
RMU_E103 is an erratum that effects some devices from the following EFM32 Series 0 products:
This erratum does not affect EFM32 Gecko, Giant gecko, or any EFM32 Series 1 devices.
C.
Steps can be taken to both detect if RMU_E103 is occurring on a specific device, and to prevent code from executing at low voltage.
Figure 1. VDD Test for RMU_E103 Current Consumption
RMU_E102 POR/BOD Reset Issue
Questions:
A. What is Errata RMU_E102?
B. What devices are affected?
C. How can I prevent this issue from affecting my application?
D. Are there plans to fix this issue?
Answers:
A.
Erratum RMU_E102 describes an issue with certain Series 0 EFM32 devices. Affected parts may see voltage regulator failure when subjected to the following scenario:
In this type of sequence mentioned above , the voltage regulator may fail to re-initialize. If this occurs, the DECOUPLE pin will continue to decay to 0V, even after VDD has recovered. In this state, the core logic is not powered, and the device will be unable to execute code or respond to a pin reset. An affected device will successfully recover from this state if power cycled.
Additionally, if a pin reset is applied prior to the Brown out detector (BOD) asserting reset, the regulator will always re-initialize successfully. The BOD threshold varies between 1.74-1.96V, so a pin reset should be asserted before VDD drops below 1.96V. The pin-reset should be held low until VDD is >1.98V, which is the maximum power-on reset threshold.
The diagrams below demonstrate an example VDD waveform that can cause the regulator initialization to fail.
Figure 1. VDD Decay and Recovery
This figure shows the proper recovery sequence, or what will happen to a working device (not affected by RMU_E102) when VDD falls to 0.9V. Here, the regulator restarts after VDD is restored, and the DECOUPLE voltage returns to 1.8V.
Figure 2. VDD Decay and DECOUPLE failure
This figure shows the failure mode for a device affected by RMU_E102 when VDD falls to 0.9V. As you can see the regulator fails to re-initialize properly, and the DECOUPLE voltage continues to fall until reaching 0V. At this point a power-on reset must be performed to recover the device.
As mentioned above, there are two workarounds to the issue.
B.
RMU_E102 is an erratum that effects some devices from the following EFM32 Series 0 products:
This erratum does not affect EFM32 Gecko, Giant Gecko, or any EFM32 Series 1 devices.
C.
To avoid issues caused by RMU_E102, the following precautions should be taken.
Writing to the VDAC (DAC) COMBDATA Register with LDMA (DMA)
I'm trying to output two sine waves to the two VDAC channels on the EFR32BG13 by reading these values from a table and writing them to the VDAC_COMBDATA register with LDMA (later I'm going to output data in the same fashion as it is received via BLE).
I setup two 16-bit buffers with the data and initialize the LDMA as follows:
A TIMER triggers the VDAC output via the PRS, and I fill the buffers accordingly when the LDMA triggers its DONE interrupt.
The problem I have is that I only get the correct output on channel 0. If I transfer longwords using the LDMA, then I get a signal from both outputs, but the output is not correct, e.g. every fourth ping-pong transfer fails, and I get 0V output for this period.
What is the correct structure to write to the COMBDATA register? How do I manage to accomplish this with a ping-pong buffer?
Our user's setup of the LDMA here is mostly correct except for one major flaw:
While this looks correct, in theory, the problem is with the attempt to use halfwords for the transfer size. While there is no issue itself with the LDMA performing a halfword read or write, it cannot do so when the target register is a memory-mapped peripheral. All write accesses to peripheral registers must be longword writes. In the case of the COMBDATA register, this actually makes perfect sense when you consider that its sole purpose is to update both VDAC output channels simultaneously.
So, in the customer's case, the solution is fairly simple. Instead of maintaining two ping-pong buffer arrays of type uint16_t, the data to be buffered needs to be stored to permit the two 16-bit output values to be read as 32 bits that are written together to the COMBDATA register. This could be done by simple ordering the data so that the 0th entry in the buffer is the first channel 1 output value (VDAC_COMBDATA_CH1DATA), the 1st entry is the first channel 0 output value (VDAC_COMBDATA_CH0DATA), the 2nd entry is the second channel 1 output value, the 3rd entry is the second channel 0 output value, etc. The same thing could be done with a typedef struct that has as its two components variables for the channel 1 and channel 0 output values.
Having made this change, the LDMA descriptors would be modified for 32-bit transfers:
If there's a need to generate a waveform on one output, then have it remain unchanged while the other channel is updated, this could be done with the original code above with the proviso that the destination for each descriptor would be &(VDAC0->CH0DATA) or &(VDAC0->CH1DATA) as needed.
NOTE: While this discussion involves the VDAC on Series 1 EFM32 and EFR32 devices, it applies identically to the DAC on Series 0 EFM32 and EZR32 devices. The requirement for aligned longword accesses to peripheral registers is universal across all EFM32, EFR32, and EZR32 devices.
How do I set the Debug Lock Word (DLW) or other locations in the lock bits or user data pages in my C program using IAR?
IAR provides a very convenient #pragma mechanism for locating variables at specific memory addresses:
This #pragma is then followed by the specific variable declaration. Programming the DLW to lock debug access is thus as simple as:
The first line specifies that the address of the following variable should be 0x0FE04000 + (127 << 2 ) = 0x0FE041FC. LOCKBITS_BASE is #defined in the CMSIS Cortex-M Peripheral Access Layer Header File for the device in question and is 0x0FE04000 for all current EFM32, EFR32, and EZR32 devices.
Naturally, the constant debug_lock_word sets the DLW to 0x0 (at the previously specified address), but what does the __root modifier do? As explained in the following IAR Technical Note...
https://www.iar.com/support/tech-notes/linker/the-linker-removing-functions-and-variables-or-external-not-found/
__root prevents the linker from removing a variable or function if it is not referred to in the main() call-tree or in any interrupt call-tree. Short of perhaps checking the state of the debug_lock_word in firmware to enable/disable debugging features, there would usually be no reason for it to be referenced in main() or elsewhere, thus the need to prevent the linker from removing it.
Obviously, this same technique can be used for any of the other words in the lock bits page. For example, to have pin resets treated as hard instead of soft resets, it's necessary to clear bit 2 of lock bits page word 122, which is configuration word 0 (CLW0), and is done with (bit 1 of CLW0 enables the bootloader and remains set in this particular example):
Locations in user data space can be programmed with constant data in the same way. For example, a product and manufacturer name could be stored as follows:
A curious user might ask "How exactly do I know this works? The .hex file format is rather cryptic looking to the untrained eye. Is there a way to parse this .hex file output from the build process and verify the expected constants are there?"
Various binary tools can be used to dump and otherwise convert .hex files, but the output from the attached hexinfo program (attached to this article for Windows machines after compiling from the sources at https://github.com/bradgrantham/hex2bin) does the job conveniently enough:
Each contiguous region in the hex file can be associated with a section of the compiled binary data. The largest is, of course, the program code itself, while the three smaller regions correspond to the product_name, manufacturer_name, and debug_lock_word constant definitions at the addresses specified by the location #pragmas that precede them.
How to Read the Pulse Counter (PCNT) in an Interrupt Handler on EFM32 Series 0 Devices
I've run into an interesting problem: If I attempt to read the pulse counter PCNTn_CNT register shortly after the edge which increments the counter, say in an interrupt handler triggered by the rising or falling edge of the GPIO pin used, the count value does not reflect the newly captured edge.
However, if I set a break point in my interrupt handler and step through the call to the PCNT_CounterGet() function, the value returned is correct! What's happening here?
This is a perfect example of the clock domain boundary crossing problem, which is what happens when a CPU running from one clock source reads a register clocked by another, asynchronous source. On EFM32 Series 0 devices, the CPU runs off the HFCORECLK while the pulse counter runs from either the LFACLK or the edges that appear on the PCNTn_S0 pin. These clocks are, of course, asynchronous, and the pulse counter runs at what is generally a much lower frequency than the HFCORECLK, so there is a sizable delay between when the PCNTn_CNT register gets updated after an edge and when the CPU core can actually see the new value.
Reading from and writing to asynchronous registers, i.e. those associated with the low-energy peripherals, is documented in section 5.2.4 Access to Low Energy Peripherals (Asynchronous Registers) of each device's reference manual, including use of the peripheral's FREEZE register, if present. Unfortunately, in the case of the pulse counter, the FREEZE register doesn't provide any help.
What really seems to be needed is some kind of flag bit indicating that an update to the CNT register is in progress. Of course, the logic driving this bit would have to use the same clock as the counter, creating a kind of Catch-22 situation.
Ultimately, the nature of this problem is that it takes some number of PCNTn_CLK clock ticks relative to HFCORECLK ticks to guarantee that the value read from the CNT register is up-to-date. Consequently, if there's no way to enforce this synchronization on the read side of the equation, can it be done by proxy using a write?
The answer is yes, thanks to the PCNTn_SYNCBUSY register, which indicates when writes to the TOPB, CMD, and CTRL registers are in progress. Given that SYNCBUSY effectively reflects the propagation of data from the HFCORECLK domain into the PCNTn_CLK domain, it's safe to assume that a synchronized write issued after the edge that triggers the GPIO interrupt in the customer's example above, will guarantee that the value read from PCNTn_CNT includes this edge.
Of course, to do this, it's necessary to know the correct register and the value to write — really rewrite — to it such that the pulse counter keeps running as configured. TOPB looks to be the best option because the value written to it is unlikely to change (or at least be changed infrequently) after initialization. So, given this, here's what the interrupt handler in question would now look like:
For convenience, TOP (via TOPB) is rewritten to its reset value. If it's not possible to know the specific value of TOP when the interrupt handler is running, simply reading TOP and rewriting that value via TOPB would also work:
Attached to this article is an example for the STK3800 Wonder Gecko Starter Kit (STK) — porting it to the STK3700 Giant Gecko or STK3600 Leopard Gecko boards would be trivial — that illustrates the use of SYNCBUSY (via the emlib PCNT_TopSet() function) to provide the synchronization needed to read CNT and have it reflect the most recent edge captured.
When the PCNT_TopSet() call is commented out of the interrupt handler, the first push of button 0 on the STK, while engaging the GPIO_ODD_IRQHandler(), will not be reflected in the count displayed on the LCD. However, setting a breakpoint in and then single-stepping through the interrupt handler allows enough LFACLK edges to propagate through the pulse counter so that the most recent edge increments the CNT register in time for the display to be updated.
To import the demo project Simplicity Studio...
How many bits wide is the Pulse Counter on EFM32 Series 0 Devices?
I ran into a discrepancy trying to get the pulse counter (PCNT2, specifically) up and running on an EFM32 Wonder Gecko device and just wanted to confirm that what I am seeing is correct. The reference manual section with the register description (section 24.5) shows the TOP and CNT fields as 16 bits. When I try to set the TOP register (through the TOPB register, e.g. PCNT2->TOPB = 0x1FF) only the lower byte is set. AN0024 says the pulse counter incorporates an 8-bit counter which is consistent with what I saw.
Can you please confirm that the register description in the reference manual is incorrect?
Actually, the Reference Manual description...
...is correct! What matters is which pulse counter you want to use. On any EFM32 device with multiple instances of a peripheral (the USART is another such example), it's critical to refer to the datasheet to see how that peripheral has been configured on the device in question.
In the case of Wonder Gecko, as the datasheet shows and to appropriate a line from Goerge Orwell's Animal Farm, "All pulse counters are equal, but some pulse counters are more equal than others."
So, in this case, the customer absolutely did observe the correct behavior because PCNT2 (and, likewise, PCNT1) are 8-bit instantiations of the peripheral. If, instead, the customer had tried PCNT0, it would've behaved as he initially expected when attempting to write a 16-bit value to the TOPB register.
Note also that emlib is aware of the width associated with each pulse counter instantiation. Attempts to write 16-bit values into the CNT or TOPB registers of PCNT1 or PCNT2 using the relevant emlib functions will generate an assertion upon execution when code is built using the debug configuration in Simplicity Studio. In this particular case, the customer wrote directly to the TOPB register, thus bypassing the error checking emlib would otherwise provide.
By convention, on all EFM32 Series 0 devices — except for the original Gecko, which has only a single 8-bit pulse counter — PCNT0 is 16 bits and PCNT1 and PCNT2, if present, are 8 bits.
Series 0 ADC Input Impedance
The ADC circuit is a 300-800 ohm resistor in series with a 2 pF capacitor, plus ESD protection diodes. There is no loading, and the maximum leakage on the input pin is 50 nA. This applies to series 0 EFM32 parts: Gecko, Giant Gecko, Tiny Gecko, Leopard Gecko, Wonder Gecko, Zero Gecko, and Happy Gecko. The equivalent diagrams in single-ended and differential mode are shown below: