8-bit Knowledge Base

      • How to create and link to a static library

        jstine | 10/292/2015 | 07:38 PM

        Static libraries contain code that is linked at compile time to the project calling it.  It can be used to provide reusable functions or to distribute code in a binary-only format (a header file will still be needed).


        To create a static library, go to File -> New -> Silicon Labs MCU Project and select Library:

        01 - New library project.png


        Write any functions you want the library to contain.  Library functions can call other library functions.  Be sure to create a header file containing prototypes for the functions you wish to be called from the linking project.  There will be no main() function in the library.  Build this project.


        02 - lib code.png


        Create a new project to link to the library (or use an existing project).

        03 - new project.png


        In this project, add the directory containing the library's header file to the include path.  Do this by going to Properties -> C/C++ Build -> Settings -> Tool Settings -> Compiler -> Includes -> Add directory path.

        04 - include path.png


        Add the library's .lib file to the linker by going to Properties -> C/C++ Build -> Settings -> Tool Settings -> Linker -> Libraries -> Add.  You must build the library project for the .lib file to be created.


        05 - link to library.png


        Add the #include for the libraries header file to the linking project.  You can now call functions from the library.

        06 - source code.png





      • Why do I2C pins have to be open-drain and not push-pull?

        cgiga | 10/292/2015 | 07:35 PM


        Why do I2C pins have to be open-drain and not push-pull?


        Setting the I2C pins to push-pull can cause damage to the devices on the bus. The reason this is an issue is that there are three parts of the I2C communication protocol specifically that can result in a direct short from power to ground:


        • Bus arbitration if there is more than one master on the bus
        • Slave clock stretching
        • ack/nack

        In these above three scenarios, it is possible for one device to be driving SDA high, while another device on the bus is driving SDA low. If the outputs are open-drain, devices can only drive low, or float (pulled-up in the case of I2C). In the above three scenarios, this means there is no conflict since the device driving low will always win on the bus.


        If the outputs are push-pull, then the only two possible states are drive low or drive high; there is no "float" state. In the above three scenarios with push-pull outputs, one device on the bus will be driving SDA low, and another will be driving SDA high, so there will be a direct short between power and ground through the two devices. This can cause damage to the devices and is not recommended.

      • Address space overflow troubleshooting

        ChrisM | 10/292/2015 | 07:31 PM


        How do I troubleshoot the "address space overflow" error in an 8051 project using Keil?


        The 8051 memory model contains several different types of segments including:

        • DATA (128 bytes)
        • IDATA (128 bytes)
        • PDATA (first 256 bytes of XDATA)
        • XDATA (up to 64 KB)
        • CODE (up to 64 KB)


        DATA, IDATA, PDATA, and XDATA all allow read and write access, whereas CODE is read only.  The memory segments are listed in order of speed and code efficiency (DATA accesses are fastest and generate the most compact code, wherease CODE accesses are the slowest and generate the least compact code).


        Keil locates variables by default depending on which of the following memory models are selected:

        • small - variables in DATA
        • compact - variables in PDATA
        • large - variables in XDATA


        Users can manually locate variables in a specified memory segment using the following macro from si_toolchain.h (provided by Silicon Labs):


        SI_SEGMENT_VARIABLE(name, vartype, memseg)



        name is the name of the variable,

        vartype is the data type (i.e. uint8_t)

        memseg is a memory segment (i.e. SI_SEG_IDATA)


        Variables that don't specify a segment or use the SI_SEG_GENERIC segment are located based on the rules defined by the specified memory model passed to the linker.


        During the link stage of the build process, the linker places all variables and functions into the appropriate memory segments.  If the number of bytes assigned to a memory segment exceeds the maximum size of the segment, the linker generates an error like:


        SPACE: DATA
        LENGTH: 0000C1H


        where SPACE and SEGMENT specifies which memory space and segment are overflowed and LENGTH specifies the size of the memory segment.


        In the example above, _DATA_GROUP_ is a segment created to hold all variables defined in the DATA segment when overlaying is used.  Overlaying allows the linker to reuse memory that can't be used simultaneously such as two local variables in two functions that aren't called at the same time.



        There are two primary methods to fix an address space overflow error: (1) change the default memory segment by changing the linker memory model or (2) manually move certain variables to other memory segments.


        Changing the Memory Model in Simplicity Studio

        1. Right click on the project in the Project Explorer view and click Properties.
        2. Navigate to C/C++ Build->Settings->General Settings.
        3. Choose a memory model from the Memory model combo box.

        Specifying a Memory Segment

        Use the SI_SEGMENT_VARIABLE() macro from si_toolchain.h as described above.



        The M51 map file generated by the linker can be a great resource for determining how much memory each module uses and to decide which variables to relocate to another memory segment to free up space in an overflowed segment.


        As an example, the EFM8UB1_Blinky project was modified to create three large variables in main(), TIMER2_ISR(), and enter_DefaultMode_from_RESET() by adding the following to the beginning of each respective function:



        uint8_t main_data_hungry[64]; // added to main()
        uint8_t interrupts_data_hungry[64]; // added to TIMER2_ISR()
        uint8_t initdevice_data_hungry[64]; // added to enter_DefaultMode_from_RESET()


        Attempting to build the project will result in several errors:

        make: *** [EFM8UB1_Blinky.omf] Error 1
        SPACE: DATA
        BASE: I:000080H
        LENGTH: 000041H

        SPACE: DATA
        LENGTH: 0000C1H


        This is because we added variables that use 192 bytes of the default memory segment, which is DATA in the small memory model.  DATA can only hold up to 128 bytes including register banks, bit data, etc.


        Looking at the top of the M51 map file, we can see that the DATA segment is using 0x10C (268) bytes, well over the 128 byte maximum.




        Further down the M51 map file, each segment and its memory usage are listed.  Unfortunately, with overlaying enabled, the _DATA_GROUP_ segment does not fit and thus can't be placed.  So we don't see any usage.


        To aid in troubleshooting, we can temporarily disable overlaying, which will create a separate segment for each module.  This way we can see each module's contribution to memory usage separately.


        Temporarily Disabling Overlaying

        1. Right click on the project in the Project Explorer view and click Properties.
        2. Navigate to C/C++ Build->Settings->Keil 8051 Linker->General.
        3. Uncheck the Enable variable overlaying checkbox.

        Once overlaying is disabled, we can rebuild the project and get a much more useful M51 map file with each module's memory usage in detail.




        Here we can clearly see that the ENTER_DEFAULT_MODE_FROM_RESET segment in the INITDEVICE module is using 0x41 (65) bytes.  Once the DATA memory segment overflows, the linker stops placing memory, so we won't see the other two large variables until we free up some memory in the DATA segment.


        Applying either of the two solutions described above would fix the errors.  For example, changing the memory model to large would place the 192 bytes of variable data in XDATA.  Similarly, we could manually place the variables in another memory segments such as IDATA, PDATA, or XDATA.


      • Package Finish Coverage for CP2103 Devices

        cgiga | 10/292/2015 | 07:18 PM


        1) What deposition process is used for the Sn plating (electroplate, immersion, or hot dip)?

        2) What is the thickness of the Sn plating?

        3) Is the Sn plating subjected to an annealing process after deposition with the purpose of mitigating Sn whiskers?

        4) If the Sn plating is annealed after plating, is the plating tested according to JESD 201?

        5) On packages that have a pad to designate pin 1, are those pads also Sn plated?


        1) The deposition process used is electroplating.

        2) Thickness of the electroplating is a minimum of 10 µm.

        3) Yes.

        4) No.  JESD 201 does not apply to components with bottom-only terminations where the full plated surface is wetted during assembly (for example: QFN and BGA components, Flip Chip bump terminations).
        5) Yes.