How can I enable debug lock (flash read protection) for my EFR32 application?
In particular, we are using Simplicity Commander to generate a hex file that combines our tokens for encryption and signing. We also use Commander to program our target and know that Commander can also lock a device on a target board with...
commander device lock
...but is there a way to enable debug lock via a hex file so that this step just happens as a matter of course when flashing our devices?
Yes, absolutely! In fact, because you are generating a hex file with tokens for use with Gecko Bootloader, it's a simple matter to modify this file to also enable debug lock.
As you're already running Commander with a series of different command line switches in order to generate everything needed for Gecko Bootloader, you just need to add one more call at the end of all of your processing:
Note in particular that should be the file you generate with Commander that contains your signing and encryption tokens. These are actually located in the lock bits page, so it's necessary to add the patch that sets the debug lock word (DLW) in this file.
Why is this the case? In theory, the DLW could be set in any hex file. Simplicity Commander or any other tool used to program the hex file into flash would write the required data wherever it needs to be located. However, if you program the tokens hex file after programming the DLW in another hex file, it's likely that your programming software (including Commander) would first erase the lock bits page, thus unlocking the device because debug lock does not take effect until after a reset.
Consequently, regardless of where or when you choose to enable debug lock, make sure it is part of the last flash programming operation performed so that it takes effect with the next reset and cannot otherwise be undone.
I'm trying to run the example code provided in AN1029: Linked Direct Memory Access (LDMA) Controller on my EFM32TG11 Starter Kit (SLSTK3301A), and it does not work. I single stepped through the code and found that the write to MSC_CTRL in this line...
...enabling atomic clear-on-read of the IFC registers does not take effect. MSC_CTRL remains unchanged from its default value of 0x1. Needless to say, this prevents the demo from running because LDMA_IRQHandler() uses this feature to clear pending interrupts.
Is atomic clear-on-IFC-read broken on TG11, or did I miss something when I ported the example from Pearl Gecko?
Alas, the customer did miss something, but not through any fault of his or her own.
The reason this example code could not set MSC_CTRL_IFCREADCLEAR is because the MSC configuration is actually locked!
How exactly would this be the case? After all, the TG11 Reference Manual shows that MSC_LOCK = 0x0 at reset, implying that the MSC configuration is unlocked, which makes perfect sense:
What the customer is unaware of here is that when his code is run on the TG11 board, it's not actually running from reset.
Specifically, TG11 ships from the factory with the bootloader described in AN0003. One of the things this code does before passing execution control to the user's application code is restore several registers to their default state. One such register that does NOT remain unchanged, however, is MSC_LOCK.
Almost everything the BOOT_boot() function found in the boot.c source file does is restore registers to their default states, so why not MSC_LOCK? Certainly, the thinking here is that because the bootloader would initialize the MSC in the event of a firmware update, it probably wouldn't be necessary to leave the MSC configuration unlocked once a firmware has been completed or if there wasn't a firmware update in the first place.
How exactly does the bootloader end up running? After all, the device is already powered when the user downloads the example code in Simplicity Studio. The key here is that a reset occurs after the flash is programmed with the user code, so all kinds of things execute before Studio brings up the debugger where it happens to be sitting obediently, ready and waiting at main(). This includes the bootloader, which, unless otherwise disabled by writing a 0 to bit 1 of Configuration Word 0 (CLW0) at offset 0x1E8 in the lock bits page, is executed by default on EFM32 Series 1.
For some users, this isn't particularly desirable behavior, so what are the possible workarounds?
There are plenty of reasons to customize the bootloader (e.g. changing the default USART), and this could be one of them.
If the factory bootloader isn't needed because firmware updates are handled in a different fashion, then disable it via CLW0 as described above.
Use the emlib MSC_Init() function to initialize the MSC. While this might only seem necessary right before programming the flash, it can be run at any time, and the first thing it does is unlock the MSC configuration.
Write the unlock key to the MSC_LOCK register using the following line of code:
The first part of this article talks about the error in the OPAMP application note and reference manual. The second part talks about how to actually make a differential amplifier with 3 opamps using the EFM32 boards.
Error in OPAMP Application Note and Reference Manual
AN0038 Operational Amplifiers covers how to make different kinds of opamp configurations using the EFM32 boards. However, it and the reference manual have a mistake in the section on making a differential amplifier with 3 opamps. They give the following equation for Vout:
This equation is a specific version of the equation for a differential amplifier. It is only valid if the resistor ladder ratio (RES_RATIO) for OPA0 and OPA2 are the same. Meaning, this equation only holds if
In the application note and reference manual, the upper R1 and R2 resistors should be switched. A more accurate diagram is shown below.
Since one can only specify the resistor ladder ratio per opamp in the form of R2 / R1, the resistor ladder configurations need to be inverses of each other for OPA0 and OPA2 in order to make the Vout equation above valid. Given the possible R2 / R1 resistor configurations, this means that only the following resistor configurations can be used:
If one wanted to use other resistor configurations (i.e. not have the resistor ratios be inverses of each other), then the generic Vout equation is the following:
How to make a differential amplifier with 3 opamps
For OPA0, the user needs to
Select an R2 / R1 resistor ratio. Again if the user plans to use the Vout equation shown previously, he/she should use a ratio of 1/3, 1, or 3 as shown in the table above and make sure the ratio is the inverse of the one chosen for OPA2
Select ground as the input to the resistor ladder. This can be done in one of two ways. The first is to select the internal VSS signal. The other way is to select the negative pad and then ground the GPIO pin corresponding to the negative pad.
Select a signal for the positive input. This can be from the positive pad or from the APORT if using a series 1 board. The positive pad refers to the designated pin being routed to the opamp input (e.g. OPA0_P or OPA0_N, see the Alternate Functionality Overview section of your board's datasheet for the specific pin mappings). Note that the negative pad can technically also be selected as the input to the positive terminal of the opamp provided that it isn't already being used (this is fine because it's really just a matter of routing the correct signals to the correct locations).
Select a signal for the negative input. This signal has to come from OPA0's output in order to configure it as a voltage follower. If using the OPA_INIT_DIFF_RECEIVER_OPA0 default macro, then this is already taken care of for you.
// Configure OPA0
OPAMP_Init_TypeDef init0 = OPA_INIT_DIFF_RECEIVER_OPA0;
init0.resSel = opaResSelR2eq0_33R1; // Choose resistor ratio to be R2 = (1/3) * R1
init0.resInMux = opaResInMuxVss; // Choose VSS as the input to the resistor ladder
init0.posSel = opaPosSelAPORT3XCH2; // Choose opamp positive input to come from APORT
For OPA1 the user needs to
Select a signal for the positive input. As mentioned above, this can be from the positive pad, negative pad, or from the APORT if using a series 1 board.
Select a signal for the negative input. Like OPA0, OPA1 needs to be configured as a voltage follower and the OPA_INIT_DIFF_RECEIVER_OPA1 default macro already takes care of this for you.
Disable the resistor ladder since it's not being used. The OPA_INIT_DIFF_RECEIVER_OPA1 default macro already takes care of this for you.
// Configure OPA1
OPAMP_Init_TypeDef init1 = OPA_INIT_DIFF_RECEIVER_OPA1;
init1.posSel = opaPosSelAPORT4XCH3; // Choose opamp positive input to come from APORT
For OPA2 the user needs to
Select an R2 / R1 resistor ratio. Again if the user plans to use the Vout equation shown previously, he/she should use a ratio of 1/3, 1, or 3 as shown in the table above and make sure the ratio is the inverse of the one chosen for OPA0
Select the location to route the output to. This can be to the main output pad (OPA2_OUT) or to a pin routed through the APORT bus.
Select a signal for the positive input. This should come from OPA0's resistor ladder and is already taken care of by the OPA_INIT_DIFF_RECEIVER_OPA2 default macro.
Select a signal for the negative input. This should come from OPA2's resistor ladder and is already taken care of by the OPA_INIT_DIFF_RECEIVER_OPA2 default macro.
Select the input to OPA2's resistor ladder. This should come from OPA1's output and is already taken care of by the OPA_INIT_DIFF_RECEIVER_OPA2 default macro.
// Configure OPA2
OPAMP_Init_TypeDef init2 = OPA_INIT_DIFF_RECEIVER_OPA2;
init2.resSel = opaResSelR2eq3R1; // Choose resistor ratio to be R2 = 3 * R1
init2.outMode = opaOutModeAPORT3YCH1; // Route opamp output to the APORT
Finally, the user needs to enable the opamps. Also, the DAC/VDAC clock needs to be enabled since opamp 0 and opamp 1 are contained within the DAC/VDAC module.
Attached is a code example that runs on PG12, MG12, BG12, and FG12.
The VDAC consists of two channels (channel 0 and 1) with separate 12-bit data registers, and each channel support two conversion modes: continuous and sample/off mode.
In continuous mode the VDAC channels will drive their outputs continuously with the data in the VDACn_CHxDATA registers.
However, in sample/off mode, the VDAC will only drive the output for a limited time per conversion, the duration be determined by the SETTLETIME field in VDACn_OPAx_TIMER register. The VDAC will drive the output for SETTLETIME fDAC_CLK cycles before tristating the output again.
Suppose the fDAC_CLK is 100kHz, and set the SETTLETIME as 100, the VDAC will drive the output pin around 1mS before tristating the output again.
The source code below demonstrates how to setup the VDAC to drive the output pin of channel 0 in sample/off mode.
void setupVDAC(void)
{
// Use default settings
VDAC_Init_TypeDef init = VDAC_INIT_DEFAULT;
VDAC_InitChannel_TypeDef initChannel = VDAC_INITCHANNEL_DEFAULT;
// Enable the VDAC clock
CMU_ClockEnable(cmuClock_VDAC0, true);
// VDAC clock source is 12 MHz internal VDAC oscillator
init.asyncClockMode = true;
// Calculate the VDAC clock prescaler value resulting in a 100 KHz VDAC clock
init.prescaler = VDAC_PrescaleCalc(100000, false, 0);
// Set reference to internal 2.5V reference
init.reference = vdacRef2V5;
// Enable channel when initialization is done
initChannel.enable = true;
// Set channel conversion mode to sample/off mode
initChannel.sampleOffMode = true;
// Set the SETTLETIME
VDAC0->OPA[0].TIMER &= ~(_VDAC_OPA_TIMER_SETTLETIME_MASK);
VDAC0->OPA[0].TIMER |= 100 << _VDAC_OPA_TIMER_SETTLETIME_SHIFT;
// Route the output of VDAC to PB12 for EFM32PG12
VDAC0->OPA[0].OUT &= ~(VDAC_OPA_OUT_MAINOUTEN | VDAC_OPA_OUT_ALTOUTEN);
VDAC0->OPA[0].OUT |= VDAC_OPA_OUT_APORTOUTEN + VDAC_OPA_OUT_APORTOUTSEL_APORT4YCH28;
// Initialize the VDAC and VDAC channel
VDAC_Init(VDAC0, &init);
VDAC_InitChannel(VDAC0, &initChannel, 0);
}
I am trying to make a self-writing LDMA to manage ADC conversions, but it doesn't work in EM2. It works when I run it in EM0 and EM1, but some of my transfers get cut off in EM2.
Answer
First, make sure that you are enabling adcEM2ClockOnDemand and singleDmaEm2Wu so that the ADC can correctly run in EM2 and communicate with the DMA.
If that doesn't fix the issue, then the problem is likely due to the use of WRI descriptors in EM2. WRI descriptors should be used as automatically-triggered transfers in a linked list, and this can cause problems in EM2.
The DMA is asleep by default in EM2. The ADC has to wake it up in order for it to perform the necessary transfers. After the ADC has cleared out it's buffer, the DMA goes back to sleep. When a WRI transfer tries to trigger on the completion of the ADC transfer also, it is indeterminate if it will be able to complete before the DMA goes back to sleep. The more WRI transfers you chain together, the less likely it is that the linked list will complete.
I am using the DMA and I need to know what order things happen in. When do all the different steps in my transfer take place?
Answer
Below is a flow chart detailing the control flow of single channel transfers in the EFM32 Series 0 DMA:
The number of transfers remaining is determined by N_MINUS_1
Looping functionality does not exist on the Gecko, Happy Gecko, and Zero Gecko. You can consider the EN bit to always be 0 for these boards.
Terminology:
Arbitration Rate: 2 ^ R_POWER
N: Total number of transfers needed. Calculated as N = (N_MINUS_1 at beginning of transfer) plus 1
REQ and SREQ: request signals selected by DMA_CHx_CTRL
Terms in all caps refer to bit fields in the DMA hardware registers. Below is a mapping of the bit fields to the register that they belong to:
DMA_LOOPx
LOOP_EN
WIDTH
DMA_IF
DMA_DONEx
CHANNEL_CFG
DST_SIZE
R_POWER
N_MINUS_1
CYCLE_CTRL
Note: CHANNEL_CFG is not a normal DMA hardware register. It is located in system memory in the Primary/Alternate Data Structure. More information about this structure can be found the Reference Manual, section 8.4.3. (DMA > Functional Description > Channel control data structure)
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.
Question: The EFM32GG Reference Manual (Rev1.20) shows the UD page occupying memory locations 0x0FE00000 – 0xFE01000 (4096 bytes in Figure 5.4 (page 17) and lists the UD size as 4 kB in Table 7.1 (page 32). The region between 0x0FE00800 – 0x0FE01000, however, appears unreadable by debugger or firmware.
What is the size of the user data (UD) page on EFM32GG (series 0), and can it be both written to and read from?
Answer: The reported 4 kB UD page size in the EFM32GG is a known documentation issue. The actual user data size for EFM32GG (series 0) is 2048 bytes and the address range is 0x0FE00000-0x0FE007FF.
The UD page can be written to and read from, while the DI page is read only. Note that the MSC functions must be used to write to the UD page.
32-bit Knowledge Base
Use the EFM32 STK Virtual COM (VCOM) port with external device
The EFM32 STK Virtual COM (VCOM) port baud rate is fixed at 115200, N, 8, 1.
The EFM32G and EFM32TG STK do not support VCOM port.
For EFM32 STK (EFM32ZG, EFM32HG, EFM32PG1, EFM32PG12, and EFM32xG11) with 20-pin Simplicity Connector
For EFM32 STK (EFM32GG, EFM32LG, and EFM32WG) without 20-pin Simplicity Connector
EFM32 及 EFR32 Lock Bits 页的擦除
EFM32 及 EFR32 的 Reference Manual 的 Memory System Controller (MSC) 一节有如下的一个表格:
其中针对 "Lock Bits (LB)" 页 "Write/Erase By" 列表述为 "Erase: Debug only" 和 "Write: Software, debug",其似乎意味着 "Lock Bits" 页只能通过 Debugger 来擦除,但事实并不是这样。
事实上,如下的代码是可以擦除Lock bits page:
这背后是什么原因使得这段代码如此特别,虽然 MSC 文档明确说不能通过软件 (Software) 擦除,但是这些代码确实能擦除 "lock bits" 页呢?
这是因为在运行这段代码时候,debugger 有连接到了芯片。
通过 debugger 来运行代码是上面表格里 "Erase: Debug only" 想要表述的真正含义。
附件是一个针对 EFM32PG12 芯片的一个示例代码(可以轻易的 port 到其他 EFM32 或者 EFR32 系列芯片),该示例代码流程如下:
1. I/O 引脚被初始化且进入 EM2,等待 STK (或者WSTK) 板上的按键 BTN0 被按下。
2. 当 BTN0 按键被按下并释放后,MSC 外设被初始化且 "lock bits" 页中的一个 lock 字被写为全0。
3. 然后,调用 MSC_ErasePage() 来擦除 "lock bits" 页。
4. 如果上面的擦除操作成功返回,"lock bits" 页被读回从而确认所有字是被有效擦除的 (变为 0xFFFFFFFF)。
5. 如果 "lock byts" 页确实被擦除, LED0 会亮起,否则 LED1 会亮起。
为了运行并测试该代码,把 STK 连接到电脑,打开 Simplicity Studio, 编译下载该代码到STK板,并点击 "Play/Resume" 按钮。 LED0 会亮起,暂停调试器并读出 0x0FE04100 位置的 flash 内容,内容会是 0xFFFFFFFF,从而证明该字是被成功擦除了。
接下来,断开调试器并把一个 CR2032 的纽扣电池插入到 STK 的电池槽。把电池槽旁边的 switch 拨到 "BAT" 位置,然后按下按键 BTN0。 LED1会亮起从而表示 "lock bits" 页没有被擦除。为了进一步验证,重新连接 STK 到 PC,选择 Simplicity Studio 的 IDE 下的 "Run → Connect to → Silicon Labs ARM Part",读出 0x0FE04100 位置 flash 内容,可以看出改字仍然为 0,从而说明擦除并未成功。
请通过以下步骤加载附件的示例代码到 Simplicity Studio:
从这个实验我们可以得到两点启示:
英文原版:
https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2018/06/07/erasing_the_lockbit-WVQL
How can I enable debug lock (flash read protection) for my EFR32 application?
How can I enable debug lock (flash read protection) for my EFR32 application?
In particular, we are using Simplicity Commander to generate a hex file that combines our tokens for encryption and signing. We also use Commander to program our target and know that Commander can also lock a device on a target board with...
...but is there a way to enable debug lock via a hex file so that this step just happens as a matter of course when flashing our devices?
Yes, absolutely! In fact, because you are generating a hex file with tokens for use with Gecko Bootloader, it's a simple matter to modify this file to also enable debug lock.
As you're already running Commander with a series of different command line switches in order to generate everything needed for Gecko Bootloader, you just need to add one more call at the end of all of your processing:
Note in particular that should be the file you generate with Commander that contains your signing and encryption tokens. These are actually located in the lock bits page, so it's necessary to add the patch that sets the debug lock word (DLW) in this file.
Why is this the case? In theory, the DLW could be set in any hex file. Simplicity Commander or any other tool used to program the hex file into flash would write the required data wherever it needs to be located. However, if you program the tokens hex file after programming the DLW in another hex file, it's likely that your programming software (including Commander) would first erase the lock bits page, thus unlocking the device because debug lock does not take effect until after a reset.
Consequently, regardless of where or when you choose to enable debug lock, make sure it is part of the last flash programming operation performed so that it takes effect with the next reset and cannot otherwise be undone.
Cannot Enable IFCREADCLEAR on Series 1 EFM32 Devices
I'm trying to run the example code provided in AN1029: Linked Direct Memory Access (LDMA) Controller on my EFM32TG11 Starter Kit (SLSTK3301A), and it does not work. I single stepped through the code and found that the write to MSC_CTRL in this line...
...enabling atomic clear-on-read of the IFC registers does not take effect. MSC_CTRL remains unchanged from its default value of 0x1. Needless to say, this prevents the demo from running because LDMA_IRQHandler() uses this feature to clear pending interrupts.
Is atomic clear-on-IFC-read broken on TG11, or did I miss something when I ported the example from Pearl Gecko?
Alas, the customer did miss something, but not through any fault of his or her own.
The reason this example code could not set MSC_CTRL_IFCREADCLEAR is because the MSC configuration is actually locked!
How exactly would this be the case? After all, the TG11 Reference Manual shows that MSC_LOCK = 0x0 at reset, implying that the MSC configuration is unlocked, which makes perfect sense:
What the customer is unaware of here is that when his code is run on the TG11 board, it's not actually running from reset.
Specifically, TG11 ships from the factory with the bootloader described in AN0003. One of the things this code does before passing execution control to the user's application code is restore several registers to their default state. One such register that does NOT remain unchanged, however, is MSC_LOCK.
Almost everything the BOOT_boot() function found in the boot.c source file does is restore registers to their default states, so why not MSC_LOCK? Certainly, the thinking here is that because the bootloader would initialize the MSC in the event of a firmware update, it probably wouldn't be necessary to leave the MSC configuration unlocked once a firmware has been completed or if there wasn't a firmware update in the first place.
How exactly does the bootloader end up running? After all, the device is already powered when the user downloads the example code in Simplicity Studio. The key here is that a reset occurs after the flash is programmed with the user code, so all kinds of things execute before Studio brings up the debugger where it happens to be sitting obediently, ready and waiting at main(). This includes the bootloader, which, unless otherwise disabled by writing a 0 to bit 1 of Configuration Word 0 (CLW0) at offset 0x1E8 in the lock bits page, is executed by default on EFM32 Series 1.
For some users, this isn't particularly desirable behavior, so what are the possible workarounds?
How to make a differential amplifier with 3 opamps using EFM32 boards
The first part of this article talks about the error in the OPAMP application note and reference manual. The second part talks about how to actually make a differential amplifier with 3 opamps using the EFM32 boards.
Error in OPAMP Application Note and Reference Manual
AN0038 Operational Amplifiers covers how to make different kinds of opamp configurations using the EFM32 boards. However, it and the reference manual have a mistake in the section on making a differential amplifier with 3 opamps. They give the following equation for Vout:
This equation is a specific version of the equation for a differential amplifier. It is only valid if the resistor ladder ratio (RES_RATIO) for OPA0 and OPA2 are the same. Meaning, this equation only holds if
In the application note and reference manual, the upper R1 and R2 resistors should be switched. A more accurate diagram is shown below.
Since one can only specify the resistor ladder ratio per opamp in the form of R2 / R1, the resistor ladder configurations need to be inverses of each other for OPA0 and OPA2 in order to make the Vout equation above valid. Given the possible R2 / R1 resistor configurations, this means that only the following resistor configurations can be used:
If one wanted to use other resistor configurations (i.e. not have the resistor ratios be inverses of each other), then the generic Vout equation is the following:
How to make a differential amplifier with 3 opamps
For OPA0, the user needs to
For OPA1 the user needs to
For OPA2 the user needs to
Finally, the user needs to enable the opamps. Also, the DAC/VDAC clock needs to be enabled since opamp 0 and opamp 1 are contained within the DAC/VDAC module.
Attached is a code example that runs on PG12, MG12, BG12, and FG12.
How to setup the VDAC to sample/off mode on EFM32 series 1?
The VDAC consists of two channels (channel 0 and 1) with separate 12-bit data registers, and each channel support two conversion modes: continuous and sample/off mode.
In continuous mode the VDAC channels will drive their outputs continuously with the data in the VDACn_CHxDATA registers.
However, in sample/off mode, the VDAC will only drive the output for a limited time per conversion, the duration be determined by the SETTLETIME field in VDACn_OPAx_TIMER register. The VDAC will drive the output for SETTLETIME fDAC_CLK cycles before tristating the output again.
Suppose the fDAC_CLK is 100kHz, and set the SETTLETIME as 100, the VDAC will drive the output pin around 1mS before tristating the output again.
The source code below demonstrates how to setup the VDAC to drive the output pin of channel 0 in sample/off mode.
Using WRI DMA Transfers in EM2
Question
I am trying to make a self-writing LDMA to manage ADC conversions, but it doesn't work in EM2. It works when I run it in EM0 and EM1, but some of my transfers get cut off in EM2.
Answer
First, make sure that you are enabling adcEM2ClockOnDemand and singleDmaEm2Wu so that the ADC can correctly run in EM2 and communicate with the DMA.
If that doesn't fix the issue, then the problem is likely due to the use of WRI descriptors in EM2. WRI descriptors should be used as automatically-triggered transfers in a linked list, and this can cause problems in EM2.
The DMA is asleep by default in EM2. The ADC has to wake it up in order for it to perform the necessary transfers. After the ADC has cleared out it's buffer, the DMA goes back to sleep. When a WRI transfer tries to trigger on the completion of the ADC transfer also, it is indeterminate if it will be able to complete before the DMA goes back to sleep. The more WRI transfers you chain together, the less likely it is that the linked list will complete.
EFM32 Series 0 DMA Flow Chart
Question
I am using the DMA and I need to know what order things happen in. When do all the different steps in my transfer take place?
Answer
Below is a flow chart detailing the control flow of single channel transfers in the EFM32 Series 0 DMA:
Terminology:
Terms in all caps refer to bit fields in the DMA hardware registers. Below is a mapping of the bit fields to the register that they belong to:
DMA_LOOPx
DMA_IF
CHANNEL_CFG
Note: CHANNEL_CFG is not a normal DMA hardware register. It is located in system memory in the Primary/Alternate Data Structure. More information about this structure can be found the Reference Manual, section 8.4.3. (DMA > Functional Description > Channel control data structure)
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.
EFM32GG Series 0 USER DATA Page Size
Question: The EFM32GG Reference Manual (Rev1.20) shows the UD page occupying memory locations 0x0FE00000 – 0xFE01000 (4096 bytes in Figure 5.4 (page 17) and lists the UD size as 4 kB in Table 7.1 (page 32). The region between 0x0FE00800 – 0x0FE01000, however, appears unreadable by debugger or firmware.
What is the size of the user data (UD) page on EFM32GG (series 0), and can it be both written to and read from?
Answer: The reported 4 kB UD page size in the EFM32GG is a known documentation issue. The actual user data size for EFM32GG (series 0) is 2048 bytes and the address range is 0x0FE00000-0x0FE007FF.
The UD page can be written to and read from, while the DI page is read only. Note that the MSC functions must be used to write to the UD page.