The bootloader can only process the bootload record which be created from a hex file with Hex2Boot tool. And the bootload record is a pure binary file composed of the bootloader commands described in 5. Bootloader Protocol of AN945.
The figure as below illustrate the detailed structure of bootload record.
The bootload record file start with a setup command to pass the flash keys to the bootloader and selects the active flash bank. The followed erase command will be decoded by bootloader and erase the select flash page. And then the Write command will be decoded by bootloader to write the payload data to flash starting at the indicated address.
The Hex2Boot can also merge the Erase and Write as one single Erase command, after get the record bootloader will erase the page firstly, and then write flash with data in record.
Whether the bootloader erase the flash page or not just depend on the bootload record. By default, only the flash page which need to be written will be erased firstly.
1.1 Entering Bootloader Mode The EFM8 device will entry bootloader mode under these three conditions. • On any reset, the bootloader will start if flash address 0x0000 is 0xFF (i.e. first byte of the reset vector is not programmed). This ensures new or erased parts start the bootloader for production programming. For robustness, the bootloader erases flash page 0 first and writes flash address 0x0000 last. This ensures that any interrupted bootload operations will restart when the interrupting event clears. • To start the bootloader on demand, the application firmware can set the signature value 0xA5 in R0 in Bank 0 (data address 0x00) and then initiate a software reset of the device. If the bootloader sees a software reset with the signature value in R0, it will start bootloader execution instead of jumping to the application. • To provide fail-safe operation in case the application is corrupted, the bootloader starts on either power-on reset (POR) or pin resets if a pin is held low for longer than 50 µs. A full list of entry pins for each device and package is available in Table 3.1 Summary of Pins for Bootloader Mode Entry on page 7 of AN945. The pin for this bootloader entry method can also be found by looking at the efm8_device.h file in the bootloader source code. There is no option to disable this entry method.
1.2 The detailed implementation of bootloader source code as below. After system reset or power on, the MCU will execute the boot_startup.asm in bootloader FW firstly. • If the flash address 0x0000 is 0xFF, MCU will jump to boot_start to start the bootloader, otherwise execute the next command. • When the bootloader sees a software reset and the signature value in R0 is 0xA5, it will jump to boot_start, otherwise will jump to pin_test for boot pin checking. • If the boot pin held low for longer than 50us, the MCU will also execute boot_start, otherwise jump to app_start to execute the application code.
; Start bootloader if reset vector is not programmed
MOV DPTR,#00H
CLR A
MOVC A,@A+DPTR
CPL A
JZ boot_start
; Start bootloader if software reset and R0 == signature
MOV A,RSTSRC
CJNE A,#010H,pin_test
MOV A,R0
XRL A,#BL_SIGNATURE
JZ boot_start
; Start the application by jumping to the reset vector
app_start:
LJMP 00H
; Start bootloader if POR|Pin reset and boot pin held low
pin_test:
ANL A,#03H ; A = RSTSRC
JZ app_start ; POR or PINR only
MOV R0,#(BL_PIN_LOW_CYCLES / 7)
?C0001: ; deglitch loop
JB BL_START_PIN,app_start ; +3
DJNZ R0,?C0001 ; +4 = 7 cycles per loop
; Setup the stack and jump to the bootloader
boot_start:
MOV SP, #?BL_STACK-1
LJMP ?C_START
What happened if the RX FIFO of EFM8LB1 I2C Slave overruns?
Answer
EFM8LB1 I2C Slave peripheral includes two separate 2-byte FIFOs on transmit and receive. When the RX FIFO is full during I2C write transfer, only the first two bytes will be stored in the RX FIFO. The first two bytes can be (Slave Address + Data Byte 0) if ADDRCHK bit is set to 1, or (Data Byte 0 + Data Byte 1) when ADDRCHK bit is 0. The reset of the bytes are thrown away. Therefore, it is responsibility of software to clear the FIFO before it overruns.
How do I change which package of a particular part Configurator uses? What do I do if Configurator does not list the package I need?
Answer
The package used by Configurator can be changed by editing the .hwconf file. Under the device tag, there will be a name field that includes the package. In the example below, QFN32 can be changed to QFP48:
How can I reduce the amount of RAM and flash used to support printf/printf_P formatter options?
Answer
Printf/Sprintf Formatter Options
printf() and scanf() have various levels of support for the C89 format specifiers (ie %d, %f, etc). However full support for all C89 formatters uses a lot of RAM and flash. For small embedded systems, this may not be practical. To reduce the RAM and flash requirements, consider reducing the formatter support based on the three options listed in the table below.
Printf/sprintf Formatter Option
Formatter Support
Large
Full C89 support
Medium
No float support (%f, %g, %G, %e, and %E not supported)
Small
Only supports %%, %d, %o, %c, %s, and %x with no support for field width or precision
To configure the printf/scanf formatter options, perform the following steps in IAR EW8051:
1. Right click the project and click Options
2. Click the General Options category
3. Click the Library Options tab
4. Choose an option from the Printf formatter and Scanf formatter drop down list
The Small option uses the least amount of RAM and flash, but only supports limited integer format options. To conserve the most memory, use the Small printf formatter option with the int16_t type.
For example:
int16_t number = 10;
printf("%d", number);
The Large option will use substantially more flash as floating point is not supported in hardware and requires software libraries on 8051 devices.
See FORMATTERS USED BY PRINTF AND SPRINTF in EW8051_CompilerReference under the The CLIB runtime environment section for complete details.
Printf_P/sprinf_P Formatter Options
Printf_P must be used when the string formatter is stored in code memory. The same formatter options are present for printf_P, but this option can't be specified using the Library options dialog. Instead developers must use one of the following Linker options:
Printf/sprintf Formatter Option
Linker Command Line Option
Large
<default>
Medium
-e_medium_read_P=_formatted_read_P
Small
-e_small_read_P=_formatted_read_P
The Large formatter option is the default and thus no linker command line option should be added to set this option.
To set the printf_P formatter option to Medium or Small, perform the following steps:
1. Right click the project and click Options
2. Click the Linker category
3. Click the Extra Options tab
4. Check the Use command line options checkbox
5. Add the appropriate command line option for medium or small as specified in the table above
See SPECIFYING READ AND WRITE FORMATTERS in EW8051_CompilerReference under the 8051-specific CLIB functions section for complete details.
Why do I receive the following error message when using IAR EW8051 with the "CODE memory" setting for "Location for constants and strings" Target setting:
// Sample Code
printf("%d", count);
// Error Message
Error[Pe167]: argument of type "char __code *" is incompatible with parameter of type "char const *"
Answer
When using the CODE memory setting, string literals will be stored in the __code memory space. The IAR 8051 implementation of printf() and sprintf() expect to find the format string parameter in RAM. Users must call 8051-specific versions of these functions when format strings are stored in __code space.
Data Memory Function
Code Memory Function
printf
printf_P
scanf
scanf_P
sprintf
sprintf_P
Additional 8051-specific functions that target code memory can be found in pgmspace.h.
See PLACING CONSTANTS AND STRINGS IN CODE MEMORY in EW8051_CompilerReference for complete details.
Some Silicon Labs 8-bit MCUs have a peripheral known as a Flash Prefetch Engine. This is required on devices that support MCU core SYSCLK frequencies greater than 25 MHz. Since the flash memory on the device has a maximum clock frequency of 25 MHz, and the MCU core can execute one byte of code per SYSCLK cycle, it becomes necessary to fetch multiple bytes of flash per SYSCLK cycle if SYSCLK exceeds the flash maximum clock speed.
For example, if the MCU core was running at 50 MHz, but the flash was still only fetching one byte per 25 MHz flash clock, the MCU core would need to be idle every other SYSCLK cycle in order to wait for new instructions. To combat this, the prefetch engine allows the device to fetch multiple bytes of flash per SYSCLK clock cycle.
Branch Instructions, variable latency:
Branch instructions generally have a variable execution time, depending on whether the branch is taken or not taken. This occurs because the core automatically assumes that the branch will not be taken, and fetches the next byte of code after the branch instruction automatically. However, if the branch instruction is executed, and it turns out that the branch is actually taken, the core has to dump any instructions that are currently executing from the branch-not-taken code, load the code from the branch-taken destination, and begin executing this code instead. For example, here is the JZ instruction latency table from the EFM8LB1 reference manual:
Clock Cycles
Mnemonic
Description
Bytes
FLRT = 0
FLRT = 1
FLRT = 2
JZ rel
Jump if A equals zero
2
2 or 3
2 or 6
2 or 8
Table 1. JZ rel variable instruction execution times
As you can see, each column for number of clocks to execute this instruction has two values - one for the branch-not-taken case (the smaller number), and one for the branch-taken case (the larger number). The branch-not-taken case will always be faster, since the core, by default, is already in the process of executing the instructions after the branch statement by the time the branch instruction is resolved. If the branch instruction resolves to 'branch not taken', the core continues executing as normal, causing no delays in execution.
For other instructions, such as SJMP, the branch is always taken, requiring that the core always take this longer route to execution:
Clock Cycles
Mnemonic
Description
Bytes
FLRT = 0
FLRT = 1
FLRT = 2
SJMP rel
Short jump (relative address)
2
3
6
8
Table 1. SJMP rel instruction execution times
Prefetch Engine's impact on instruction execution times:
Another thing to note, however, is that the instruction execution time is now dependent on the FLRT setting in the prefetch engine. This setting has the following description in the EFM8LB1 reference manual:
"Flash Read Timing: This field should be programmed to the smallest allowed value, according to the system clock speed. When transitioning to a faster clock speed, program FLRT before changing the clock. When changing to a slower clock speed, change the clock before changing FLRT."
FLRT Setting
Description
0
SYSCLK < 25 MHz.
1
SYSCLK < 50 MHz.
2
SYSCLK < 75 MHz.
Effectively, this means that FLRT=0 means 1 byte of flash will be fetched per SYSCLK cycle, FLRT=1 means two bytes will be fetched at once, and FLRT=2 means that four bytes of flash will be fetched at once. This setting also determines the flash clock timing. FLRT=0 means the flash clock will be SYSCLK, FLRT=1 means the flash clock will be SYSCLK/2, and FLRT=2 means that the flash clock will be SYSCLK/3.
How does this impact instruction execution times? When a jump instruction is executed, and the jump is taken, the core must now load the code from the destination address. This will take one flash clock cycle, during which the core must be idle. In the case of FLRT=1 or FLRT=2, one flash clock cycle equals multiple core cycles - either 2 or 3 cycles, respectively. Some additional latency is also added due to having to load the new flash address, dumping the instructions that are currently being executed in the core, etc. Generally, the jump-not-taken execution time will be +3 clock cycles and +5 clock cycles for FLRT=1 and FLRT=2, respectively.
More variation in execution times:
However, these numbers are not absolute rules. More quirks with the flash prefetch engine can speed up or slow down execution, depending on the location of the jump instruction itself, as well as the destination location.
As an experiment, the SJMP instruction was evaluated on an EFM8LB1 device running at SYCLK=72MHz, FLRT=2. For the first test, the SJMP instruction was placed at address 0x0100, with its destination address modified to be between 0x0102 and 0x011A.
SJMP Rel
Cycles
Destination Address
Address Mod 4
0
3
0x0102
2
1
3
0x0103
3
2
3
0x0104
0
3
3
0x0105
1
4
3
0x0106
2
5
5
0x0107
3
6
6
0x0108
0
7
6
0x0109
1
8
6
0x010A
2
9
8
0x010B
3
10
6
0x010C
0
11
6
0x010D
1
12
6
0x010E
2
13
8
0x010F
3
14
6
0x0110
0
15
6
0x0111
1
16
6
0x0112
2
17
8
0x0113
3
18
6
0x0114
0
19
6
0x0115
1
20
6
0x0116
2
21
8
0x0117
3
22
6
0x0118
0
23
6
0x0119
1
24
6
0x011A
2
Table 2. SJMP instruction at 0x0100
As you can see, the SJMP execution time varies anywhere from 3 cycles (when the destination is within 4 bytes of the SJMP instruction), all the way to 8 cycles (when the destination is farther away from the SJMP instruction, and the destination address ends in 0x3, 0x7, 0xB, or 0xF (effectively, if the address modulo 4 equals 3).
Another test was performed, this time with the SJMP instruction at address 0x00FE:
SJMP Rel
Cycles
Destination Address
Address Mod 4
0
4
0x0100
0
1
4
0x0101
1
2
4
0x0102
2
3
5
0x0103
3
4
6
0x0104
0
5
6
0x0105
1
6
6
0x0106
2
7
8
0x0107
3
8
7
0x0108
0
9
7
0x0109
1
10
9
0x010A
2
11
7
0x010B
3
12
7
0x010C
0
13
7
0x010D
1
14
7
0x010E
2
15
9
0x010F
3
16
7
0x0110
0
17
7
0x0111
1
18
7
0x0112
2
19
9
0x0113
3
20
7
0x0114
0
21
7
0x0115
1
22
7
0x0116
2
23
9
0x0117
3
24
7
0x0118
0
Table 1. SJMP instruction at 0x00FE
Again, the SJMP instruction execution time varies, this time with an additional clock cycle added to all instructions. The fastest execution, again, was when the destination was close to the SJMP instruction address, while all instructions ending in 0x3, 0x7, 0xB, and 0xF performed worse.
Minimizing execution times:
Several observations can be made that can be used to minimize instruction execution times for branch instructions, in cases where highly optimized branches are needed.
If possible, put the destination address very close to the jump instruction.
Place the destination address on an even flash boundary. If FLRT=1, place the destination so that its address modulo 2 equals zero. If FLRT=2, place the destination so that its address modulo 4 equals zero.
Place the jump instruction on a similar boundary, as in #2. If FLRT=1, place the jump instruction so that its address modulo 2 equals zero. If FLRT=2, place the jump instruction so that its address modulo 4 equals zero.
Attached to this topic is a program called SJMP_TEST.asm, which can be used to measure the instruction execution times of jump instructions. This is performed by monitoring the value of TIMER3 (clocked by SYSCLK) once the jump instruction is executed, and the core reaches the destination.
In embedded systems, analog measurements are often required for both voltage and current sources. Common variable current sources include photodiodes and phototransistors, as well as some forms of other sensors, such as temperature sensors. In most cases, current sources are converted into a voltage measurement, usually through the use of a sense resistor, or an amplifier plus a sense resistor to provide a low output impedance of the measured signal. However, there is a way to directly measure these current sources by taking advantage of the architecture of the SAR ADCs present on Silicon Labs MCUs.
The method described here, which I will refer to as ADC current integration, requires zero external components, with sampling times potentially many times faster than a simple current sense solution.
1. ADC Architecture
Firstly, it helps to review the architecture of a SAR ADC. A simple diagram is below:
Fig 1. ADC SAR Architecture, simplified
When the ADC is enabled, and a particular pin is selected as the ADC's input, the SAMPLE_SWITCH is closed, allowing CSAMPLE to charge to the signal voltage available on the input pin. When a conversion is initiated, the SAMPLE_SWITCH is opened, allowing the voltage on the CSAMPLE capacitor to stay stable while the ADC performs the conversion. CPIN is merely the pin's parasitic capacitance, which is usually very small, but near the same order of magnitude of the CSAMPLE capacitor.
Generally, with a voltage source, the signal on the ADC_INPUT_PIN is of very low impedance, charging the relatively small CPIN and CSAMPLE capacitors very quickly to the input voltage.
However, with current sources, the current is usually converted to a voltage by using a simple current sense resistor. This can effectively increase this output impedance significantly, increasing the amount of time required for the sampling capacitor to charge before a sample can be taken.
2. Capacitor integration
An alternative to the current sensing resistor solution is to integrate the current as a voltage on the capacitor. A basic property of a capacitor is that the voltage (V) on a capacitor is equal to the charge (Q) on the capacitor divided by its capacitance (C):
Equation 1. Capacitor voltage with respect to charge and capacitance
Since charge is merely equal to current (I) times time (t), we can re-write the equation as:
Equation 2. Capacitor voltage with respect to current, time, and capacitance
As you can see, given a fixed amount of time for the capacitor to charge, and a fixed capacitance, the voltage on the capacitor is directly proportional to the amount of current flowing into the capacitor. This means that a capacitor, such as an ADC's sampling capacitor, can be used to convert a constant current into a voltage merely by letting it charge for a fixed period of time.
3. Implementation
Implementing this technique is relatively straightforward:
Select the current source as the ADC's input pin.
Ground the ADC's sampling capacitor and the input pin to discharge its parasitic capacitance.
Disconnect ground from the ADC input pin so that the current source can now charge the sampling capacitor.
Wait for some fixed amount of time (discussed in section 6. Determining the integration period) to allow the current to charge the capacitor.
Initiate a conversion, disconnecting the sampling capacitor from the input pin.
Since the capacitance on the input is fixed, and the user can sample the input for a fixed amount of time, the voltage read on the ADC will be proportional to the current generated by the current source.
4. A real-world example
As previously mentioned, photodiodes are a common example of a sensor that generates a current, rather than a voltage, output. For this example, an infra-red photodiode was selected from Digikey: PD204-6B, IR Photodiode
According to this device's datasheet, this photodiode will generate a current between 1.5uA and 3.5uA, depending on the lighting conditions.
In this example, we will use an EFM8SB2 8-bit MCU, which, according to its datasheet, has a pin capacitance of 20pF, and an ADC sampling capacitance of 28pF, for a total input capacitance of 48pF.
Current-sense resistor technique:
If we wish to convert this current (3.5uA maximum) to a voltage that can be read by the ADC (0-1.65V with a PGA gain of 1.0), we will need to add a very large current sense resistor across the input pin. A value of 350k Ohms will produce a voltage of 1.225V at 3.5uA (V=IR). However, the time constant to charge the input capacitor, with this parallel sense resistor, can be quite large. Here is a simulation of this circut in LTSpice:
V1 represents VDD of 3.3V
I1 represents the photodiode, sourcing 3.5uA
C_sample represents the sampling and pin capacitance in parallel
R1 is the current sensing resistor
Fig 2. Sample voltage, sense resistor
As you can see, this technique effectively provides a measurable voltage from the current source, but, even after 100us, the capacitor is not completely charged to the expected 1.225V.
Integration technique:
Removing the sensing resistor, the current source is now feeding directly into the capacitor. A similar LTSpice simulation has been created with three example current sources, 3.5uA, 2.5uA, and 1.5uA.
Fig 3. Sample voltage, current integration
In this case, you can see that the capacitor voltage is linear with respect to time. It is also proportional to the input current. For example, where the previous example took 100us to reach 1.225V, this method allows the 3.5uA current source to reach 1.225V in only 16.8us. If we fix this time and measure the other two sources, we get 0.875V for the 2.5uA source and 0.525V for the 1.5uA source.
Comparing the currents to 3.5uA, we get proportions of:
3.5uA = 1
2.5uA = 0.714
1.5uA = 0.428
Comparing the resulting voltages at 16.8us, we get proportions of:
1.225V = 1
0.875V = 0.714
0.525V = 0.428
Exactly the proportions between the given currents. This implies that this technique can be used to accurately measure a current source.
5. Testing it on the bench
To test this technique on a bench, a Silicon Labs EFM8SB2 8-bit MCU was used. This was chosen because this MCU has both an ADC and an adjustable current DAC (IREF).
For this project, the ADC was set to take a single 10-bit conversion when manually writing '1' to the ADBUSY bit in the ADC0CN0 register. The IREF module was set to generate a current between 0 and 63uA (in 1 uA increments) on P0.7.
To take a current sample, the ADC first selects the IREF pin as its input. The pin is then set to push-pull so that it is grounded to make sure that all residual capacitance is discharged. The pin is then set back to being an analog input and the IREF is enabled with a given setting.
A small delay allows the IREF output to charge the ADC's sampling capacitor. The ADC is then triggered to start a conversion. The output of this conversion is proportional to the input current.
The source code for the measurement function is given below:
uint16_t ADC_GetIntegratedSample(uint8_t irefCurrentSetting)
{
uint16_t sample;
// Switch ADC to measure P0.7
ADC0MX = ADC0MX_ADC0MX__ADC0P7;
// Discharge pin and sampling capacitance
IREF0CN0 = 0;
P0MDOUT |= P0MDOUT_B7__PUSH_PULL;
// Enable Current Source
P0MDOUT &= ~P0MDOUT_B7__PUSH_PULL;
IREF0CN0 = irefCurrentSetting;
// Delay to integrate sample
NOP();NOP();NOP();
// Take measurement
sample = ADC0_GetSample();
// Disable current source
IREF0CN0 = 0;
return sample;
}
The ADC result was recorded for every IREF step (0-63uA). The IREF current was also measured using a multimeter for each of these steps. The plot of these two measurements is below:
Fig 4. ADC Count vs. IREF current
The results, shown here, indicate that the ADC count very closely matches the curve of the actual IREF current. This shows that this technique can be used in a real-world application to effectively and quickly measure the current from a current source by simply using the device's ADC, using no external components.
Please see the attached .zip file for this example project.
6. Determining the integration period
Given that the charge time for the capacitor is proportional to the amount of current flowing into the capacitor, how do we determine the optimal sampling period for a given maximum current?
Firstly, let us re-arrange the previous Equation 2 so that we solve for time instead of voltage:
Equation 3. Integration period
Since t becomes smaller as I becomes larger, it makes sense for I to represent the maximum current that our sensor will produce, since, given a large enough current, the period would be too small for us to generate with our MCU.
Similarly, V should represent the largest voltage that our ADC can accurately measure. This would give us the largest range of values from the ADC, increasing accuracy. This value should also take into account the less-than-ideal properties of the circuit that can reduce the linearity of the capacitor voltage. For example, at higher currents, the ESR of the charging circuit can end up becoming the limiting factor on current being delivered to the capacitor at higher voltages.
C, of course, should be the total capacitance seen by the current source on the input pin. For the EFM8SB2 MCU, this includes, typically, 20pF of pin capacitance as well as 28pF from the ADC's sampling capacitor.
Calculating the maximum integration period
In a real-world application, calculating the maximum capacitor charge voltage must take into account the non-ideal components of the charging circuit. Generally, the charging circuit will have some non-trivial amount of equivalent series resistance. This can be modeled in our circuit as a series resistor, as shown here:
Fig 5. Equivalent charging circuit with ESR
As previously mentioned, the maximum voltage that the capacitor should be charged to should fall within the linear region of the capacitor voltage charge curve. As the voltage on the capacitor increases, this ESR may begin to limit the current to the capacitor rather than the current source. This occurs because, as the voltage on C_samp rises, the voltage on R_esr decreases (since V_samp + V_esr must equal V_src). At a point, the voltage across R_esr will be so low that the current through R_esr (by way of Ohm's law) will be lower than the current that the current source is able to supply. The current into the capacitor will effectively be limited by this resistance, not the current source. This has the effect of making the voltages on the capacitor after this point non-linear since, as the voltage on the capacitor rises, the voltage on the resistor continues to decrease, further decreasing the series current. From this point on, the charge curve on the capacitor will then resemble Fig 2, rather than Fig 3.
As an example, the previous EFM8SB2 firmware example was modified so that the IREF current source generated a maximum current of 508uA, while integration for each measurement was performed over 204ns:
Fig 6. Nonlinear measurements due to the effect of ESR
Here, it's obvious that the effect of the ESR has impacted our measurements to no longer be linear with respect to the current generated by the current source. This problem can be avoided by shortening the integration period, lowering the maximum voltage seen on the capacitor at the time of sampling. This has the effect of increasing the minimum voltage seen on R_esr, which increases the minimum current through R_esr. If this minimum current is greater than the maximum current from the current source, R_esr will not be a limiting factor.
Considering the circuit in Fig 5, the voltage on C_samp can now be defined as V_src - V_esr. Replacing V_samp in the previous Equation 3 with this gives us:
Equation 4. Integration period, substituted sampling capacitor voltage
We can then re-arrange the equation and, using Ohm's law to replace V_esr / I_max with R_esr, we get the following, simplified equation:
Equation 5. Integration period, simplified
This equation also gives us a theoretical maximum current supply from the current source since, if V_src / I_max is less than R_esr, the sampling time would be negative, indicating that no region of the capacitor's voltage over time would be linear.
Calculating the maximum sampling capacitor voltage for the linear region
Substituting in Equation 2 into Equation 5 for C_samp, we get the following equation when solving for the maximum voltage on the capacitor:
Equation 6. Maximum capacitor voltage
This equation defines the maximum capacitor voltage that will be seen on the capacitor before the series resistance will impact the linearity of the voltage on the capacitor over time.
7. Example integration period calculation
As an example, given that V_src (in this case, VDD) = 3.3V, an input capacitance of 48pF, an ESR of the circuit of 5k Ohms, and a maximum current of 0.1mA, we can calculate the amount of time we need to let the sampling capacitor charge by the following:
Equation 7.Example integration period calculation
Solving this equation gives ust = 1.34us. With a SYSCLK of 24.5 MHz, each SYSCLK period would equal 40.8ns. This gives us 1.34us / 40.8ns = 32.94 SYSCLK period. This means, with a maximum of 0.1mA current input, we can let the current source charge our sampling capacitor for up to 32 SYSCLK periods before the voltage on the capacitor starts to become non-linear.
Using Equation 6, we can also calculate the maximum voltage that will be seen on the sampling capacitor: V = 3.3V - (5k Ohm / 0.1mA) = 2.8V
As a confirmation, we can also use Equation 2 to calculate the resulting voltage after charging the capacitor for 1.34us at 0.1mA: V = (1.34us * 0.1mA) / 44pF = 2.8V
8. Steps, summarized:
To implement this technique:
Determine the maximum integration time using equation 5. - If this number is zero or negative, the ESR for the measurement circuit is too large for the given current, and this technique will not work. - If this period is too small to be effectively generated by the MCU, you may add an external capacitance to the pin to increase the integration period.
Connect the current source directly to the ADC input pin.
Enable the current source, allowing it to charge the capacitance on the ADC's input pin, including the ADC's sampling capacitor.
Wait for the period (or less) determined in step 1.
Trigger an ADC sample. The result will be proportional to the input current, and should not exceed the voltage calculated from equation 6.
9. Resources:
Attached to this article is a .zip file that contains:
The datasheet for the example photodiode
The two LTSpice simulation circuits
The example project for the EFM8SB2
Note: if using the EFM8SB2 STK with this example project, the resistor R1066 will need to be removed, since it connects P0.7 to a pull-up resistor for the I2C bus on the board.
On the 8051 MCUs, which have 256 bytes of RAM, how can I locate my variables and data in the upper 128 bytes, so that I can reserve the lower 128 bytes for another purpose?
Answer
On the 8051 MCUs, the lower 128 bytes bytes of RAM is the "data" space and is accessible by direct and indirect addressing, while the upper 128 bytes of RAM, or "idata," is available only by indirect addressing. To place a variable in idata, you can use the following type of declaration for the variable or array:
idata char myvariable;
or
idata unsigned char array[128];
Processor access times for idata are slower than for data. In general, it is recommended to let the compiler automatically place variables in memory where it sees fit, as it can perform certain performance and space optimizations, but if you have a specific use case that warrants manual placement of variables in the RAM space, then you can use the "idata" keyword in your variable declaration.
On the C8051F38x, can I use the USB FIFO space for general purpose XRAM if the USB module is not using that memory? In other words, if I am only using Endpoints 0 and 1, can I use the remaining Endpoint 2, 3 and remaining free space in the USB FIFO space as general purpose XRAM?
Answer
On the C8051F38x, you can use the USB FIFO space as general purpose XRAM as long as the active Endpoint FIFO memory in this address space remains untouched and the guidelines in section 14.2 "Accessing USB FIFO Space" of the C8051F38x Reference Manual (page 94). Thus, if you are only using Endpoints 0 and 1, you can use the memory at locations 0x0400 to 0x073F as general purpose XRAM. The USB FIFO access guidelines are as follows (see section 14.2 for more information):
1) The USB Clock must be active and greater than or equal to twice the frequency of SYSCLK (USBCLK >= 2 x SYSCLK) because the USB FIFO memory is clocked from the USB clock.
2) The USB FIFO Access Ennable bit (USBFAE) in the EMI0CF register must be set to '1.'
When the USBFAE bit is set to '0' (default), the memory region between 0x0400 - 0x07FF is mapped to the normal on/off chip XRAM. When this bit is set, the USB FIFO memory is mapped to these locations, as shown in the following figure.
To locate a variable at a particular location in XDATA (including the USB FIFO space if the above conditions are met), you can use either the "_at_" directive:
xdata unsigned char myVariable _at_ 0x0402;
or use a command line linker directive. For more information on this technique, please refer to the following Keil article:
8-bit Knowledge Base
The detailed structure of bootload record
How does the EFM8 device enter bootloader mode
What happened if the RX FIFO of EFM8LB1 I2C Slave overruns?
Changing part package in configurator
IAR EW8051 printf/printf_P formatter options and code size
IAR EW8051 printf() error Pe167 when storing constants and strings in CODE memory
Branch instruction variable execution time on devices with a flash prefetch engine
Using ADC to measure a current source with no external components
Locating Variables and Data in idata
Accessing Unused USB FIFO Space as General Purpose XRAM