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.
A customer comparing the USB voltage regulators on the Series 0 and Series 1 Giant Gecko devices noticed that the required capacitances for VREGI (VBUS) and VREGO are different. In fact, they're actually reversed on Series 1 vs. Series 0:
VREGI
VREGO
Documentation
4.7 µF
1 µF
p.7 of AN0002.0 (revision 1.48) and AN0046
1 µF
4.7 µF
p. 27 of AN0002.1 (revision 1.50) and EFM32GG11 Reference Manual
Given that certain packages for Series 1 Giant Gecko provide a pin-compatible upgrade path from Series 0, this could certainly cause some confusion. Is this a mistake?
While pin-compatibility purposes ought to dictate that the USB regulator on Giant Gecko Series 1 uses the same input and output capacitances as on Series 0, this is not the case. Those familiar with other EFM32 Series 1 (and EFR32) devices might recognize that the 4.7 µF output load capacitor is the same value as is used for the output DC-to-DC converter. In this respect, it makes sense that these voltage regulators have comparable requirements to maintain the stability of the output load and use the same recommended 4.7 µF capacitor.
So, customers upgrading their USB designs from Series 0 Giant Gecko to Series 1 will want to take note of this and make sure that the 1 µF capacitor is placed on VREGI while the 4.7 µF capacitor is placed on VREGO. Also, it's important to note that the capacitor for VREGO can be within the range of 1 to 10 µF depending on the load requirements with 4.7 µF being a nominal value suitable for most applications.
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
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.
USB Voltage Regulator Capacitance Requirements on EFM32 Giant Gecko
A customer comparing the USB voltage regulators on the Series 0 and Series 1 Giant Gecko devices noticed that the required capacitances for VREGI (VBUS) and VREGO are different. In fact, they're actually reversed on Series 1 vs. Series 0:
Given that certain packages for Series 1 Giant Gecko provide a pin-compatible upgrade path from Series 0, this could certainly cause some confusion. Is this a mistake?
While pin-compatibility purposes ought to dictate that the USB regulator on Giant Gecko Series 1 uses the same input and output capacitances as on Series 0, this is not the case. Those familiar with other EFM32 Series 1 (and EFR32) devices might recognize that the 4.7 µF output load capacitor is the same value as is used for the output DC-to-DC converter. In this respect, it makes sense that these voltage regulators have comparable requirements to maintain the stability of the output load and use the same recommended 4.7 µF capacitor.
So, customers upgrading their USB designs from Series 0 Giant Gecko to Series 1 will want to take note of this and make sure that the 1 µF capacitor is placed on VREGI while the 4.7 µF capacitor is placed on VREGO. Also, it's important to note that the capacitor for VREGO can be within the range of 1 to 10 µF depending on the load requirements with 4.7 µF being a nominal value suitable for most applications.
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: