8-bit Knowledge Base

      • EFM8BB3 Lock byte location

        Alan_S | 07/210/2016 | 08:06 PM


        Where is the lock byte located in my EFM8BB3 device?


        Regardless of the flash size, the Code Security Page containing the lock byte is always located at the same address. The Code Security Page is from address 0xFA00 to 0xFBFF on the 16k, 32k, and 64k EFM8BB3 devices.

      • EFM8LB1 DAC Maximum Output Voltage and Current

        Stephen | 07/204/2016 | 06:48 PM


        What is the max output voltage and max sink/source current on the EFM8LB1 voltage DAC?


        1. The output voltage is a fraction of the DAC reference. The DAC reference can be one of the following:

        • VDD
        • External reference via the VREF pin. Max voltage on VREF pin is VIO, and max VIO is VDD.
        • Internal 1.2V or 2.4V reference via the VREF pin

        Therefore, max output of the voltage DAC is VDD.


        2. The max sink/source current on the voltage DAC is |2 mA| per the the Load Regulation specification in Table 4.1.12 of the datasheet.




      • 1 wire UART with open drain TX

        jstine | 07/204/2016 | 06:40 PM


        I want to configure the UART to support a 1 wire bidrectional interface.  Can I configure the TX port as open drain?


        It is possible to configure the UART TX pin to be open drain. If you are using configurator, it will issue a warning for this, but the warning can be ignored. If you are not using configurator, you can set the TX pin to be open drain by clearing bit 4 of P0MDOUT.  When using the UART this way, it is important to ensure that the two devices to not transmit at the same time.

      • Disabling Individual PCA Channel Outputs

        BrianL | 07/204/2016 | 06:31 PM

        C8051 and EFM8 MCUs contain a timer module called the Programmable Counter Array (PCA). This module consists of a timer and several Capture/Compare channels. Each of these channels can provide a PWM or Frequency output without any CPU intervention. 

        Each channel can be programmed individually, and channel outputs can be enabled through the crossbar. Once a channel is disabled on the crossbar, its pin reverts to the settings in the particular port register for that pin. However, enabling or disabling the individual channels through enabling/disabling their outputs on the crossbar can be problematic.


        Firstly, Channels must be enabled or disabled in order - i.e., you cannot enable channel 2 without enabling channel 1. Likewise, you cannot disable channel 1 without first disabling channel 2. If channel 2 is the last enabled or disabled channel, it may be enabled or disabled freely, without interacting with previously enabled or disabled channels. It would be impossible to disable channel 0, for example, and leave channel 1 and channel 2 routed out.




        Secondly, removing functions from the crossbar at run-time can cause other problems. For example, if other functions that have a lower priority than the PCA on the crossbar are enabled, enabling or disabling PCA channels will shift these functions to different pins. This can be partially solved by subsequently setting the skip bit for the disabled PCA channel pin, but, since this instruction cannot be executed simultaneously with the crossbar-removal instruction, there will be some amount of time where all crossbar functions after the PCA are shifted. This could cause glitches in these other functions.

        // Disable PCA channel 2 output (assuming P0.2 for this example)
        XBR1 = (XBR1 & ~XBR1_PCA0ME__FMASK) | XBR1_PCA0ME__CEX0_CEX1;
        // Glitch! Next XBAR function after PCA channel 2 is now moved to P0.2!
        // Skip PCA channel 2 pin (P0.2)
        P0SKIP |= 0x02;
        // Next XBAR function is now moved back from P0.2 to its previous location


        The Alternative
        An alternative to the crossbar method is to exploit the behavior of the PCA channel settings. If a channel's Capture/Compare Mode register's TOG and PWM bits are cleared, the PCA channel output will be forced HIGH (100% duty cycle) immediately. Therefore, it is simple, if the channel needs to be disabled, but the output needs to be HIGH, to individually disable a channel by performing the following:


        // Disable a channel with 'HIGH' output

        However, it is slightly more complicated if the output must be driven LOW. You can exploit the fact that the pin will only be weakly pulled high when the pin is set to open-drain. In this case, a pull-down resistor will pull the channels pin to be low:



        // Disable PWM on P0.1
        P0MDOUT &= ~P0MDOUT_B1__BMASK;

        If the output needs to be driven LOW by the output driver (and not just pulled down by a resistor), the ECOM bit can be cleared whenever the output has been set to LOW. This will keep the output low. This does, however, require some delay in waiting for the channel output to move to the correct state - the other methods are instantaneous.



        // Declare PCA_CH1 to be bit 1 of P0 register
        sbit PCA_CH1 = P0^1;
        // Wait for P0.1 (PCA channel 1) to transition LOW
        while (P0_1 == 1);
        // Clear the ECOM bit to keep the channel output LOW
        PCA0CPM1 &= ~PCA0CPM1_ECOM__BMASK;


        To facilitate a quicker change, the channel's match register can be updated to be closer to the current PCA counter value, so that the match occurs sooner.


      • High-Frequency Switching Converter using PCA Frequency Out and ADC Window Compare

        BrianL | 07/204/2016 | 06:28 PM

        This article describes a method to drive switching converters with a high-frequency clock output, rather than the traditional PWM output at lower frequencies, in order to reduce switching converter inductor size, and thus reduce BOM cost and footprint area.



        Switching converters are commonly used to efficiently step-up or step-down voltages within embedded systems. These converters use an inductor to store or transfer energy to the load in the system. This inductor is periodically switched on to transfer energy from the supply into the magnetic field of the inductor. The inductor, when the supply is switched off, then transfers its energy into the load. These converters are generally switched on and off by a PWM signal, the characteristics of which can influence the behavior of the converter.


        In this example, a Boost Converter will be discussed. Boost converters are switching converters that generate an output voltage that is greater than their input voltage. More information about boost converters can be found here: https://en.wikipedia.org/wiki/Boost_converter



        Continuous Mode
        Generally, boost converters are operated in "continuous" mode. This means that the inductor in the converter is not fully discharged (i.e. current in the inductor does not reach zero) between switching cycles. The formula for determining the output voltage of a continuous mode boost converter is rather simple:




        Where Vo equals the output voltage, Vi equals the input voltage, and D equals the duty cycle percentage. In this case, the output voltage can be varied by simply changing the duty cycle of the PWM of the switching element. This mode does come with one caveat, however - the inductor must be large enough to store the energy required by the system during its charge and discharge cycles. What this means, effectively, is that the slower the switching frequency, the longer the inductor has to charge and discharge, and thus the inductor must be larger. Larger inductors are, of course, more expensive, so generally boost converter designs favor higher switching frequencies over lower switching frequencies.


        Note: As switching frequencies increase, losses also increase within the switching element of the circuit (usually a mosfet), so there is an upper limit on switching frequency once these losses become prohibitively large.


        All of Silicon Labs' 8-bit MCUs (C8051, EFM8) have the ability to generate PWM outputs with varying duty cycles using the PCA module, so they are well-equipped to drive boost converters. However, the maximum PWM frequency is often as low as 95.7 kHz (24.5 MHz divided by 256 for 8-bit PWM), which is rather slow by switching converter standards. This means that, generally, 8-bit MCUs operating switching converters in continuous mode will require rather large, and thus rather expensive, inductors.


        There are many online calculators that can help you determine the required components in a continuous mode boost converter, such as the one here: https://learn.adafruit.com/diy-boost-calc/the-calculator


        For example, if we have the design requirements of:

        Vin = 3V

        Vout = 12V

        Iout = 20mA

        Switching Frequency = 95.7 kHz


        We will need to run our switching converter at 75% duty cycle with a 147uH inductor.


        Discontinuous Mode

        An alternative to continuous mode is "discontinuous" mode. In this mode, the inductor current is allowed to reach zero during the discharge period of the switching cycle. This has the side-effect of complicating the formula for the output voltage:




        Where L is the inductor value, Io is the output current, and T is the switching period (the inverse of the switching frequency). As you can see, the formula is more complicated, and still contains the duty cycle percentage as a dependency, but it has introduced additional dependencies that we can use to generate the desired output, even with a fixed duty cycle. For example, with everything else fixed, if we decrease both T and the inductor size L proportionally, the output characteristics will remain the same. This means that we can use an arbitrary duty cycle, and then increase the switching frequency as needed in order to reduce the inductor size (and cost).


        The PCA, once again, has a feature that can be useful in this mode: Frequency Output generation. In this mode, a 50% duty cycle frequency output can be generated, up to SYSCLK divided by 2, or 12.25MHz in the normal case. At a more reasonable switching frequency of 3.062MHz (SYSCLK/8), we can repeat our previous example with discontinuous mode:


        Vin = 3V

        Vout = 12V

        Iout = 20mA

        Switching Frequency = 3.062MHz

        Duty Cycle = 50%


        With this, the required inductor size is reduce to 2.04uH! That's approximately 1/72nd the size of the continuous mode with PWM example, for the same output characteristics.


        Comparing inductors at ~2.2uH vs ~150uH, that are otherwise comparable:
        SRN4026-151M : 150uH, 220mA: $0.18 @1000 : 4mm x 4mm

        MLZ2012A2R2M : 2.2uH, 210mA: $0.058 @1000 : 2mm x 1.25mm


        As you can see, this smaller inductor results in a BOM cost reduction of 12.2 cents, or 68% reduction. The footprint is also reduce by 11.5mm^2, or 72%.


        Example Circuit and Firmware


        As a proof of concept, a circuit and associated firmware has been developed.


        In the example above, the characteristics of the circuit are static. As long as Vin is 3V, and the load continues to draw 20mA at 12V, the MCU merely needs to output a 3.062MHz square wave to the switching circuit to maintain a stable output. If the load draws less than 20mA at 12V, the output voltage will continue to increase until equilibrium is reached. Without any sort of feedback mechanism, we cannot be sure of the output voltage if our load varies.


        In the below circuit, a voltage divider has been provided to allow the MCU to measure the output voltage, and thus create a feedback loop, allowing us to change the behavior of the output at runtime. Additionally, a dummy load, represented by R4 and the LED, have been attached to the output:




        The firmware was written for an EFM8BB1 MCU, though this could be ported to any 8-bit MCU with a PCA module and an ADC with the Window Compare feature (i.e. almost all of Silicon Labs' 8-bit MCUs).


        The PCA is configured to output Channel 0 to pin P0.1, with a frequency output of 3.062MHz. The ADC is configured to sample on pin P0.3 at 300kHz, using Timer 3 overflows to trigger conversions. The ADC is configured to only trigger an interrupt if an ADC sample falls outside of the expected voltage range, using the Window Compare feature. With everything configured, the entire feedback loop is contained within the ADC ISR:



        	uint16_t sample;
        	// Clear Window Compare interrupt flag
        	ADC0CN0_ADWINT = 0;
        	// Store the ADC sample
        	sample = ADC0;
        	if (sample > MAX_COUNTS)
        		// Disable PWM
        		P0MDOUT &= ~P0MDOUT_B1__BMASK;
        		// Set LT Value, Clear GT Value
        		ADC0LT = MIN_COUNTS;
        		ADC0GT = 0xFFFF;
        	else if (sample < MIN_COUNTS)
        		// Enable PWM
        		P0MDOUT |= P0MDOUT_B1__PUSH_PULL;
        		// Set GT Value, Clear LT Value
        		ADC0LT = 0;
        		ADC0GT = MAX_COUNTS;



        If the ADC takes a measurement that is greater than the ADC0GT value, or less than the ADC0LT value, this interrupt will fire. If the measurement is within this range, nothing will happen. Once in the ISR, if the measurement was greater than the expected maximum value, the frequency output is disabled. If it is less than the expected value, the frequency output is re-enabled. The output is effectively disabled by turning the port to open-drain mode, so that the pin is pulled low by the resistor R1, turning off the MOSFET Q1.


        The MAX_COUNTS is defined to be the ADC code that represents 9.5V. MIN_COUNTS represents 8.5V. This should effectively limit the output voltage to 8.5-9.5V.


        The output of the circuit with this code, on an oscilloscope, is here:



        Channel 1 is the output voltage. Channel 2 is the frequency output that is applied to the circuit's BOOST pin. As you can see, this firmware activates the frequency output when the voltage is below 8.5V, and disables the frequency output when the voltage is above 9.5V.


        In practice, the usage of the ADC in Window Compare mode requires very little CPU overhead. In my measurements, with this circuit, the CPU is active for approximately 12us inside the ISR, twice every 8.9ms. The total CPU overhead is then approximately 0.14%. Decreasing the output capacitance will have the effect of requiring more frequent updates, as the output voltage will take less time to charge to the maximum limit, and less time to discharge to the minimum limit.


        Here is the circuit with the BOOST pin connected to the MCU:



        And here is with the BOOT pin disconnected:


        The output voltage, in this case, drops back down to Vin, which is less than required to light the LED.


         Attached to this case are both the schematic "boost.sch" (in Eagle .sch format), and the firmware project "BoostConverter.zip", to be used with Simplicity Studio. Additionally, a spreadsheet to help calculate the needed inductor size, given the rest of the design requirements, is attached as "Boost_Inductor_Calculator.xlsx".


        Note, this example used enabling/disabling the frequency output as its feedback mechanism. There is another option that wasn't explored - modifying the output frequency at runtime. Instead of turning the frequency output completely off, the frequency can be adjusted to increase or decrease the desired output voltage, according to the formula previously given.



      • RTC Low Frequency Oscillator (LFO) LOADCAP and BIASDOUBLE variance

        BrianL | 07/204/2016 | 06:15 PM

        Many of the low-power 8-bit MCUs have a Real Time Clock (RTC) with an integrated Low Frequency Oscillator (LFO). These devices are the C8051F97x, C8051F912/F902, C8051F99x, and the EFM8SB1 families.


        This oscillator is designed to provide a more accurate clock compared to the legacy Self-Oscillate mode (the only non-crystal mode found on some devices, such as the C8051F93x family). This oscillator is also calibrated to run at approximately 16.4 kHz by default after reset. This calibration is loaded as the reset value of the LOADCAP field of the RTC0XCF register. The calibration also relies on BIASX2 (or BIASDOUBLE) in the RTC0XCN0 register being OFF. Altering the values of these two fields after reset will impact the output frequency of the LFO.

        Turning BIASX2 ON will increase the frequency of the LFO. Decreasing LOADCAP will also increase the frequency of the LFO.


        The LOADCAP value required to reach 16.4 kHz varies from part to part, as does the change in frequency with respect to one lsb change in this value. However, measurements from one EFM8SB1 device, across LOADCAP and BIASX2 values, are displayed below.




        The measurements are attached to this artcle as LFO_LOADCAP_F.xlsx.

      • Disassembly filled with "MOV R7, A"

        BrianL | 07/204/2016 | 06:09 PM


        When viewing the disassembly of one of Silicon Labs 8-bit MCUs, I often run into sections that are filled with the assembly instruction:

        MOV R7, A



        What is this code doing? Why is my device filled with these instructions?



        This code is actually the by-product of the disassembly view attempting to decode flash that has been erased. When flash is erased, all bits return to '1'. This results in the memory being fill with, effectively, bytes of 0xFF. The 8051 instruction that corresponds to 0xFF is 'MOV R7, A'. You can see this erased flash in the memory viewer:



      • What data types are supported by the Keil C51 compiler for Silicon Labs 8-bit MCUs?

        BrianL | 07/204/2016 | 06:09 PM


        What data types are supported by the Keil C51 compiler for Silicon Labs 8-bit MCUs? Can I use float, double? What about 64-bit integers?


        The complete list of data types supported by Keil C51 is listed here: http://www.keil.com/support/man/docs/c51/c51_le_datatypes.htm


        64-bit data types (i.e. 64-bit integers, double) are not supported. If using the 'double' keyword, the type declared will actually be a 32-bit floating point number, i.e. a float, rather than a 64-bit floating point number.

      • Reserving code space in Keil C51

        BrianL | 07/204/2016 | 06:06 PM

        It is often necessary to reserve code space on a device so that it can be used for some other purpose. EEPROM emulation is a common example. If the linker is allowed to locate code in the area that is used for EEPROM, the code will get erased when the EEPROM area is erased. 

        You can direct the linker to avoid placing code in particular areas of flash memory by adding particular linker directives. 


        For example, if I want the linker to avoid placing code between 0x1000 and 0x1FFFF, I can perform the following:


        If using the LX51 extended linker, use the linker directive RESERVE:


        RESERVE (C:0x1000-C:0x1FFF)

        If using the BL51 linker, use the linker directive CODE. This works in the opposite manner as RESERVE, in that is specifies the area in which the linker can place code.



        CODE (0-0x0FFF, 0x2000-0xFFFF)


        In Simplicity Studio, these directives can be added to the "Additional Flags" field under [Project]>[Properties]>[C/C++ Build]>[Settings]>[Keil 8051 Linker]>[Miscellaneous]



      • Enum size in Keil C51

        BrianL | 07/204/2016 | 06:02 PM


        How is an enum stored when using Keil C51? How many bytes are used for an enum value, and what are the possible values?


        An enum is effectively a signed integer with a potential value range from -32768 to +32765. However, an enum can be stored in either one or two bytes, depending on what values are assigned to it. If an enum does not have a value less than -128 or greater than 127, it is effectively stored as a signed char, taking only one byte. If a value outside of this range is used, it is stored as a signed int (two bytes) instead.



        // Variables of this type will be stored in one byte
        // since all enum values can be stored in an signed char
        typedef enum { a = 0, b = -128, c = 127, } singleByte_t; // Variables of this type will be stored in two bytes
        // since an enum value can be greater than 127! typedef enum { e = 0, g = 128, } doubleByte_t;