The Project board is for sharing projects based on Silicon Labs' component with other community members. View Projects Guidelines ›


      • My adorable spy robot

        St_Nino | 01/26/2016 | 07:24 PM

        I made this cute little piggy as a school project last semester. The project was motivated by this penguin robot used by researchers:

        No clue, who I ended up making it look like a pig.




        The things I needed:

        • Raspberry Pi B+
        • two WT11 Bluetooth Classic modules
        • UART to USB converter
        • a webcam
        • two servo motors
        • power bank for Raspberry Pi
        • 4 batteries to power up the servos
        • a few 3D printed parts and a car frame kit

        This is what Piggy has been eating:


        And schematics about it:


        Things missing from the schematics: GPIO pins 18 and 23 are asserted. While building this robot those were used for debugging purposes but somehow I forgot to delete them from the code.


        A short video about my robot:





        The pink box contains:





        I had Python code in the both ends. Source files are as an attachment. I know they are a bit messy, but that's the way school projects tend to be. 

      • ZigBee Temperature Sensors with EM357 and Si7013

        A_A_Ron | 01/18/2016 | 12:04 AM

        Here's some code from my Hack-a-Gecko project last summer. I realized shortly after the project that my efforts were becoming quickly obsolete, but I've decided to post it anyways, because why let it go to waste?


        A big component of my project was that I wanted to connect a relative humidity and temperature sensor to the EM357 and report the data using the ZigBee Cluster Library. Since there wasn't any interface for this in the Ember ZNet 5.6.0 stack, I decided to roll my own.


        My first step was to choose a sensor and make sure it could be read by the EM357. I discovered that the Si7013, Si7020, and Si7021 are all I2C-based and have the same address and commands. This looked good to me because I could write one interface and then be able to use all three sensors interchangeably in this and in future projects.


        What's the difference between each of these sensors? The Si7021 has higher RH accuracy than the Si7020, and the Si7013 has the same high accuracy plus support for dual-sensor setups. The dual-sensor option is interesting to me because it has an address select pin; if this pin is pulled high in hardware, it will change to its secondary I2C address. This would allow an Si7013 to coexist on the same I2C bus as another Si7013 (or Si7020 or Si7021). I thought it was really cool and made it a goal to support dual sensors in my code.


        For testing the hardware, I used the Si70xx-EB postage stamp modules and the EM35x breakout board. The Si7013USB-DONGLE kit conveniently provided one of each module, but I didn't need the USB stick or ribbon cable for this project. I just used wires soldered to the test points on the module to connect to the EM35x breakout board.




        On the EM357 side, I needed to decide which GPIO to use for SCL and SDA. The EM357 can set either serial controller to operate in I2C mode (according to the datasheet, where it is referred to as "Two Wire Interface".) I decided to use SC2, which meant that PA1 would be used for SDA, and PA2 would be used for SCL. I chose this based on the default configuration in which SC1 is used as UART for debugging and SC2 is used as SPI or I2C for an external flash IC. I just needed to make sure I wouldn't interfere with the external flash, should I add an OTA bootloader.


        One thing to note is that while the Si70xx modules have decoupling capacitors for the IC, they do not have pullup resistors for the I2C lines. Therefore, I need to supply my own resistors. Fortunately, this is easy to do with the EM35x breakout board. I used the prototyping area to place resistors from each I2C GPIO to VBRD, then added pin headers to connect the external module.




        The next step is to read the sensor in software. I hit a bump on discovering that the HAL library has access routines for UART and SPI, but not for I2C. Luckily, I2C is not a very complicated protocol, so it's not hard to write my own. To make it easy for my colleague to load the code into his workspace, I packaged it as an AppBuilder plugin. I'm cautious to take this approach for hardware access code, since it is platform-specific and would need to be modified if one wanted to use a different serial controller. Keep this in mind if you want to download my plugin; maybe I could consider it more of a template for an I2C driver.


        The EM35x datasheet is helpful in explaining what registers need to be accessed to use I2C (or "TWI"). The first step is to change the serial controller mode to I2C; this is a simple register write:


        SC2_MODE = SC2_MODE_I2C;


        The clock rate for SCL also needs to be set. This is done by using SC2_RATELIN and SC2_RATEEXP to create a clock divider. The target rate is 100 kbps for standard mode, and 400 kbps for fast mode. However, there is a note in the datasheet that the EM35x generates an SCL low period of 1.25us at 400 kbps, and some devices may require 1.3us at that rate. To avoid compatibility issues, I set the clock divider to give a rate of 375 kbps:


        SC2_RATELIN = 15;
        SC2_RATEEXP = 1;



        Sending I2C commands is done by setting the SC2_TWICTRL1 register to the value corresponding to the frame segment needed (start, stop, send, or receive). When the register is clear, the action is complete. I initially used an infinite loop to wait for completion. The problem is that if you try to address a device that doesn't exist on the I2C bus, the segment will never complete. So to avoid getting stuck in the loop, I changed to a for loop that would time out. I also reset the watchdog to avoid resets while waiting for slow devices.


        #define TWI_TIMEOUT 10000
        EmberStatus emAfPluginTwiGenerateMasterFrame(int32u segment)
          SC2_TWICTRL1 = segment;
          //This can turn into an infinite loop if the frame is never received.
          //Therefore, we mark it as a failure if a certain timeout is reached.
          for (int32u timeWaited = 0; timeWaited < TWI_TIMEOUT; timeWaited++) {
            if (!(SC2_TWICTRL1 & segment)) {
              return EMBER_SUCCESS;
          return EMBER_ERR_FATAL;



        And now I can add wrapper functions for each of the frame segment types:


        EmberStatus emAfPluginTwiStart()
          return emAfPluginTwiGenerateMasterFrame(SC_TWISTART);
        EmberStatus emAfPluginTwiStop()
          return emAfPluginTwiGenerateMasterFrame(SC_TWISTOP);



        For the read and write commands, the register SC2_DATA is used for the data being read or written. When writing data, the SC2_TWISTAT register indicates if NAK was received.


        EmberStatus emAfPluginTwiWriteByte(int8u byte)
          EmberStatus st;
          SC2_DATA = byte;
          st = emAfPluginTwiGenerateMasterFrame(SC_TWISEND);
          if (st == EMBER_SUCCESS) {
            if (SC2_TWISTAT & SC_TWIRXNAK) {
              return EMBER_ERR_FATAL;
            } else {
              return EMBER_SUCCESS;
          return st;



        When reading data, the SC2_TWICTRL2 register is used to indicate whether to respond with ACK or NAK.


        EmberStatus emAfPluginTwiReadByte(int8u* byte, boolean ack)
          if (ack) {
            SC2_TWICTRL2 = SC_TWIACK;
          } else {
            SC2_TWICTRL2 = 0;
          EmberStatus st;
          st = emAfPluginTwiGenerateMasterFrame(SC_TWIRECV);
          if (st == EMBER_SUCCESS) {
            *byte = SC2_DATA;
          return st;



        And this is all that's needed! These four frame segments can then be strung together to initiate complete I2C transactions. I provided wrappers for the three most common transaction types: write, read, and write/read with repeated start.


        EmberStatus emberAfPluginTwiWrite(int8u address, int8u* wData, int8u wlen);
        EmberStatus emberAfPluginTwiRead(int8u address, int8u* rData, int8u rlen);
        EmberStatus emberAfPluginTwiTransaction(int8u address, int8u* wData, int8u wlen, int8u* rData, int8u rlen);



        Feel free to download the plugin source to see the implementation details.


        With the I2C interface ready, I set out to read the sensor and populate the ZigBee cluster attributes with meaningful data, which is a more typical use for an AppBuilder plugin. Since I wanted to include the dual-sensor setup, this plugin will let the user specify up to two ZigBee endpoints - one for each sensor. If a sensor is present, it will optionally update the Temperature Measurement and Relative Humidity Measurement clusters on the selected endpoint. Both clusters are optional to allow for cases such as a temperature-only device that doesn't need humidity data.




        When the plugin is initialized, it runs an Si70xx Detect routine. This is an idea I got from the EFM32 driver. It attempts to read the Device ID register from the sensor address. If it gets a response, that means that there is a sensor present on the I2C bus and the returned value indicates which family it belongs to. I also get to try out the write/read transaction from the TWI plugin.


        void emAfPluginTempSensorSi7013Detect()
          int8u commands[] = {SI7013_READ_ID2_1, SI7013_READ_ID2_2};
          int8u result[8];
          EmberStatus status;
          status = emberAfPluginTwiTransaction(SI7013_ADDR, commands, 2, result, 8);
          if (status == EMBER_SUCCESS) {
            sensorId = result[0];
          } else {
            sensorId = INVALID_SI70XX_ID;
          status = emberAfPluginTwiTransaction(SI7013_SEC_ADDR, commands, 2, result, 8);
          if (status == EMBER_SUCCESS) {
            sensorIdSecondary = result[0];
          } else {
            sensorIdSecondary = INVALID_SI70XX_ID;



        Knowing the sensor family is helpful in populating the range and tolerance attributes. Both the Temperature Measurement cluster and Relative Humidity Measurement cluster have similar attributes. These are the MeasuredValue, MinMeasuredValue, and MaxMeasuredValue attributes, which are signed 16-bit integers in the Temperature Measurement cluster, and unsigned 16-bit integers in the Relative Humidity Measurement cluster. There is also the optional Tolerance attribute, which is an unsigned 16-bit integer in both clusters.


        The units represent 0.01 degrees Celsius and 0.01% relative humidity. Fixed point notation like this is a common convention in ZigBee attributes. Because ZigBee is intended to be easily adopted on a wide variety of small, low-power embedded devices, the floating point datatype is generally not used.


        The MinMeasuredValue and MaxMeasuredValue attributes represent the possible operating range of the sensor, and the Tolerance attribute represents the accuracy of the measured value. The datasheet readily provides these values. For the Temperature Measurement cluster, the plugin will set MinMeasuredValue = -4000, MaxMeasuredValue = 8500, and Tolerance = 40. For the Relative Humidity Measurement cluster, MinMeasuredValue = 0, MaxMeasuredValue = 10000, and Tolerance = 300. If the Si7020 is used, the Tolerance attribute needs to be set to 400. This is where the detection routine comes in handy. If it finds the Si7020 device ID, it can update the attributes accordingly. Now I don't need to rebuild my application whenever I want to plug in a different sensor!


        The easiest way to take a measurement is to use the Hold Master Mode on the Si70xx. Since the EM35x supports clock stretching, all it takes is to initiate a write/read transaction, and when it completes, the measurement is done. In my debug application, I found that it took about 18 milliseconds per sensor to complete the transaction and print the results on the CLI. According to the datasheet, the measurement can take up to 22.8 ms! I'd rather let the application do other things while the sensor is taking a measurement; perhaps the EM35x can go to sleep and save some power. I changed over to use No Hold Master Mode, in which I initiate a measurement, immediately return, and then check back later for results. I decided to go with a nice round 25 ms delay. After the delay, I read the values, update the attributes, and then trigger a callback so that the application can get access to the resulting data. More importantly, this also provides the status code to the application, so appropriate action can be taken on any errors.


        What I really wanted to know is if No Hold Master mode actually reduces the power consumption by a noticeable amount. Time to do some measuring! I connected an EFM32 starter kit and used its VMCU expansion pin to power the EM35x breakout board. This let me take energy measurements with Simplicity Studio.




        I want to only measure the power consumption of the EM357 and the Si7013, so I removed all the jumpers from LED's and other peripherals to cut them off. Because I do want to include the Si7013 power consumption, I kept the jumper between the breakout board and radio module power domains connected. Here's what I saw:




        Hey, what's that ringing?! Even when I pulled all the jumpers, I saw this unwanted current draw whenever supplying any power to VBRD. No such noise was present on VMOD, and removing the radio module had no effect. Merely powering a bare board was drawing too much current! Finally, I tracked it down to an RS-232 transceiver IC that was powered by VBRD even when the RS-232 jumpers were removed. I personally would rather be able to take power measurements than use RS-232, so I took the hostile approach and desoldered it.




        All right, now I've got clean power measurements. Here's the current consumption when measuring humidity and temperature in Hold Master mode:




        And here's what it looks like with No Hold Master mode:




        In Hold Master mode, I can see the EM357 running at full force for the whole conversion time, using over 9 mA - no good! By letting the EM357 idle while the temperature sensor is taking measurements, a very large energy savings is realized. From the power curve, I can see what I think are the individual RH and temperature conversions, followed by a valley when the conversions are done but the 25 ms timer hasn't expired to let me know to read back the values.


        And it's done! While trying to get a colleague to build and run my application, I learned that modifying random stack code makes sharing quite difficult. I quickly learned that the fastest way is to say "here's a plugin folder, just drop it in /plugins/ and go!" So I bundled my code as plugins - a bit hacky, but makes sharing easy! If you'd like to download and try these plugins, follow these steps:


        • Close Ember Desktop / Simplicity Studio.
        • Copy the individual plugin folders into app/framework/plugin/.
        • Reopen Ember Desktop / Simplicity Studio and your project .isc files. If you didn't remember to close before step 2, you have to close all open .isc files and Rescan the stack.
        • The new plugins should now be available in the Plugins tab as "Two Wire Interface" and "Temp/RH Measurement - Si7013".
        • Optionally, add endpoints for any sensors you have connected, and enable Temperature Measurement and/or Relative Humidity Measurement Server clusters on those endpoints. If you want to be able to select any cluster, you can select the ZigBee Device Type to "ZigBee Custom". Be warned that AppBuilder now has to go through every cluster and attribute and unlock both Client and Server for you, so this would be a good time for a coffee break. I have seen this operation take several minutes.
        • Select the plugins and hit Generate to have them included in your application.