Skip navigation
Home > All Places > WICED Smart Bluetooth > WICED Smart Bluetooth Forums > Blog

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

 

 

                When programming on the WICED Smart platform you are operating on our kernel. The kernel is responsible for the timing and handling of all processes related to the chip. The terms that you hear used commonly in embedded coding—timers, interrupts, BLE events, handlers, callbacks, etc.—are all interactions with the kernel. Not surprisingly, they’re the only way to interact with the kernel—and, some interaction with the kernel must take place in order for any of your code to be executed outside of the create function.

 

                Because you’re operating on a kernel, there is no main function. Instead, there is a “create” function which executes once on every power-up. Also embedded in the kernel is a watchdog timer. If any statement in one of your callbacks (explained below) takes more than 2 seconds to execute, the kernel will reset the chip to terminate the process—your code is sure to fail with an infinite loop in there.

                Before you embark on creating your own applications, it’s important to have a feeling for the layout of a basic application and how to interact with the kernel at a basic level.

 

Registering for callbacks

 

                There are three very important callbacks that will be utilized in almost every single application you create. They are almost always registered in the create function. For all of the following callback functions, you must do three things:

 

  1. Declare the function
  2. Define the function
  3. Register the function as a callback

 

The “connection_up” callback is called every time the device establishes a connection with a master device. Upon connection, one will generally want to stop advertisements. Additionally, you may wish to initialize a sensor or carry out other tasks that are only performed when in connection.

 

//register the callback in create fx

bleprofile_regAppEvtHandler(BLECM_APP_EVT_LINK_UP, called_on_conn_up);

 

The “connection_down” callback is called every time the device disconnects from its master device. Generally, you will restart advertisements in this function. Additionally, you may wish to de-initialize sensors or anything else that may conserve power while you are not in a connection in not in need of.

 

//register the callback in create fx

bleprofile_regAppEvtHandler(BLECM_APP_EVT_LINK_DOWN, called_on_conn_down);

 

The “advertisement_stopped” callback is called when the device has been advertising and has surpassed its set advertisement period without having entered a connection (advertisement period customized below). Without this callback function, the app will go dead once advertisements stop because the app never sets up a process to reinitiate them (there are ways around this: interrupts, timers, etc.). Naturally, we then want to put something in this function which restarts advertisements under some circumstance.

 

//register the callback in create fx

bleprofile_regAppEvtHandler(BLECM_APP_EVT_ADV_TIMEOUT, called_on_adv_stopped);

 

 

Registering Timers

 

                The timers are very important when you are first learning the use the WICED platform. They provide an extremely easy approach to interacting with the kernel without having to deal with interrupts (which will be explained in a later post).

 

The timers, which must be instantiated together, call two respective functions every time the timer completes a cycle. The regular timeout always calls its function once per second. On the other hand, the “fine timeout” calls its function however frequently you wish (within reason). If you set the fine timeout to be called in the range of microseconds (below 5ms) it will significantly inhibit the timing of the kernel and likely disable all BLE transmissions.

 

The timers can be started and stopped at your will using the WICED API.

 

Add to your create function:

 

    bleprofile_regTimerCb(fine_timeout, one_sec_timeout);

 

Define and declare the callback functions:

 

          static void one_sec_timeout( UINT32 count );

          static void fine_timeout( UINT32 finecount );

 

Altering fine timer:

 

          const BLE_PROFILE_CFG hello_sensor_cfg = {

                /*.fine_timer_interval            =*/ 1000, // ms

          }

 

Start/Stop APIs:

 

    bleprofile_StartTimer();

    bleprofile_KillTimer();

 

Customizing Advertising Interval and Timeout

 

                This won’t come in handy until the completion of your first app, when you will be attempting to optimize your power consumption. The WICED platform allows you to customize the duration of “high” advertising (more frequent/powerful transmissions) as well as the subsequent “low” advertisements (less powerful, less frequent transmissions). At the end of both of these durations, if we have registered for an “advertisement_stopped” callback, it will be called.

 

           const BLE_PROFILE_CFG hello_sensor_cfg = {

                /*.fine_timer_interval        =*/ 1000, // ms

                /*.default_adv                =*/ 4,    // HIGH_UNDIR

                /*.button_adv_toggle          =*/ 0,    // pairing button

                /*.high_undirect_adv_interval =*/ 32,   // slots

                /*.low_undirect_adv_interval  =*/ 1024, // slots

                /*.high_undirect_adv_duration =*/ 30,   // seconds

                /*.low_undirect_adv_duration  =*/ 300,  // seconds

           }

 

                For further reading, refer toHow to Write WICED Smart Applications. You will find longer lists of event callbacks that are at your disposal.

 

Jacob W. Torres

 

 

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

 

 

When using a microcontroller with a kernel, interrupts are the most fundamental way to interact with that kernel. In order for the push of a button to turn on an LED we must register that button as an interrupt, and toggle the LED within the interrupt_handler function that you will declare, define, and register as a callback with the kernel.

 

If all you wish to do is push a button that turns on the LED, there is very quick and easy way to register for interrupts on the WICED platform:

 

                Configure the push button in the GPIO configure definition.

 

              const BLE_PROFILE_GPIO_CFG interrupt_example_gpio_cfg = {

                  {GPIO_PIN_WP, GPIO_PIN_BUTTON, 13,

                    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},

 

                  {GPIO_SETTINGS_WP, GPIO_SETTINGS_BUTTON, GPIO_SETTINGS_LED,

                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

              };

 

                Define, declare, and register the interrupt handler (handler must have a UINT8 parameter).

 

              bleprofile_regIntCb((BLEPROFILE_SINGLE_PARAM_CB)interrupt_handler);

 

                Toggle the LED within interrupt handler.

 

              void interrupt_handler(UINT8 gpio) {

                  bleprofile_LEDBlink  (50, 50, 3);   

                }

 

Interrupts, on the other hand, that are necessary for other, higher volume, higher speed/frequency applications require a different method of instantiation. There are a few more steps as well as more parameters to take into account. If you require interrupts for anything other than a single push button the following method is necessary to use:

         

  1. Define and declare your interrupt handler function.
  2. Configure interrupt mask.
  3. Register your interrupt handler using the mask.
  4. Configure the pin as an interrupt.

 

The interrupt handler must be defined and declared as a function that takes two parameters, one of which being an 8-bit integer, the other a pointer.

 

                            static void interrupt_handler (void* parameter, UINT8 arg);

 

The interrupt mask is an array of three 16 bit integers. The mask is passed as a parameter while registering for an interrupt in the following line of code. The three integers refer to the three ports of GPIOs. For the purpose of instantiating GPIO 4 as an interrupt, the

following mask would suffice:

 

                            UINT16 masks[3] = {(1 << 4), 0 , 0}; //replace 4 with GPIO number

 

But if you wished to access a GPIO outside of port 0, for instance pin 24, the mask would look like this:

 

              UINT16 masks2[3] = { 0, (1 << 8), 0};

              //port 1 starts at 16, 24 is 16+8, mask is set to 8

 

Below the mask we’ll register the interrupt handler function using the above mask as a parameter in order for the interrupt handler to be called on the appropriate GPIO interrupt.

 

              gpio_registerForInterrupt(masks, interrupt_handler, NULL);

 

In the above registration of the interrupt, when pin 4 receives an interrupt, the interrupt handler will be called and execute whatever code it contains.

 

But pin 4 doesn’t receive interrupts until its configured to. So, the final step is to configure it. The following code is worthy of copying and using for most interrupts. The third parameter can be changed to either rising edge or both edges.

 

              gpio_configurePin(0, 4, GPIO_EN_INT_RISING_EDGE, GPIO_PIN_OUTPUT_LOW);

 

The attached sample code implements the interrupt in the create function where you will see the last three steps executed sequentially.

 

              UINT16 masks[3] = {(1 << 4), 0 , 0};

              gpio_registerForInterrupt(masks, interrupt_handler, 0);

              gpio_configurePin(0, 4, GPIO_EN_INT_RISING_EDGE, GPIO_PIN_OUTPUT_LOW);

 

Now to complete our final project, all we must do is toggle the GPIO within the interrupt handler. The easiest way to do this is to call the following function (see API directory for detailed parameters):

 

              bleprofile_LEDBlink(50, 50, 3);

 

If using this API be sure that you properly configure your GPIO configuration array (as seen in prior posting of this project).

 

The attached sample firmware shows all these aspects put together, so, when loaded the LED flashes on every push of the button (sample firmware uses GPIO 0 not 4).

 

The second method is well suited for receiving interrupts from sensors or anything else attached to one of your serial busses. The interrupt pin from the sensor should be hardwired directly to the GPIO you wish to register as an interrupt (if the interrupt on the sensor is open-drain, pull it up with a 10K).

 

Registering for interrupts from sensors is another topic in itself which we will cover in a future blog posting. In summary, interrupts are a fundamental way of interacting with the kernel via push button and sensor interrupts.

 

Jacob W Torres

 

 

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

JacobT_81

How to Toggle a GPIO

Posted by JacobT_81 Jul 21, 2015

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

 

 

    To toggle a GPIO, paste the following code into your program:

 

          #define GPIO_NUM      8

          #define PIN           GPIO_NUM%16

          #define PORT          GPIO_NUM/16

          gpio_configurePin(PORT, PIN, GPIO_OUTPUT_ENABLE | GPIO_INPUT_DISABLE, GPIO_OUTPUT_HIGH);

          gpio_setPinOutput(PORT, PIN, GPIO_OUTPUT_HIGH);

 

    It really is that simple, despite some confusion on the topic. All you have to do it change the pin number, and toggle the parameter high and low. There are, in fact, some special cases to take into account, but for the most part these lines of code are all you need to toggle a GPIO. gpio_configurePin must be called only once, gpio_setPinOutput is the only one that must be called thereafter.

 

    Description of parameters:

                    gpio_configurePin(PORT, PIN, PARAMETER, HIGH/LOW)

        gpio_setPinOutput(PORT, PIN, HIGH/LOW);

 

    When referring to a pin, however, we use two separate numbers. First we use the port number, next the pin number. There’s nothing special about these numbers, they just correspond the description below:

 

                    GPIO 00-15            PORT 0

                    GPIO 16-31            PORT 1

                    GPIO 32-39            PORT 2 

 

    For the HIGH/LOW parameter, always put a zero, one, or a corresponding reference.

 

    The PARAMETER is what defines the behavior of the GPIO. Paste the provided code into any app function, and control-click one of the parameters that’s in place. You’ll see a list of every possible parameter to put in here. This is where confusion stems from, because the same API is being used to instantiate inputs, outputs, interrupts, etc. For the purposes of toggling a GPIO as an output, leave the code above as I’ve written it.

 

    The second API call is only used after initial configuration of an output GPIO. The parameters are easy to work with and identical to parameters 1, 2, and 4 of the configure API.

 

    There’s one additional thing to take into consideration. There is a GPIO configuration array at the top of every sample app. This is only to be used if you wish to utilize the APIs that they register pins for. For example, in order to blink an LED using the API below, you must configure pin 13 (LED on Tag 4) within that array.

 

bleprofile_LEDBlink(10, 10, 3);

 

    But utilizing these APIs can also create problems. By instantiating pin the 13 in the GPIO configuration array you relinquish control of the GPIO to the kernel. Meaning, if you attempt to use both LED APIs and manually toggle the LED GPIO in the same app, you may get unexpected behavior. Choose one or the other to be safe.

 

Jacob W Torres

 

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

JacobT_81

Project 1 Wrap-Up

Posted by JacobT_81 Jul 21, 2015

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

 

 

          In order to transmit sensor data via BLE notification, all we’re going to do is combine the preceding two sample applications and alter a few details. We’re going to slightly alter our GATT database to accommodate for the volume of data we’ll be sending. Additionally, our transmission process will be altered to accommodate for data larger than one byte.

 

          For the sake of accuracy, when we send data from the HTS221, we multiply the decimal values by 10 (our platform doesn’t support decimal, float values). These scaled-up numbers will often exceed one byte, but we must send those values one byte at a time.

 

          As a result, in the sample firmware, the length of the GATT characteristic has been extended from 1 byte to 5: 2 bytes for humidity, 2 for temperature, and one as a gap between the two values (for readability).

 

          CHARACTERISTIC_UUID128 (0x0029, HANDLE_HTS221_VALUE_NOTIFY,

                                  UUID_HTS221_CHARACTERISTIC_NOTIFY,

                                  LEGATTDB_CHAR_PROP_NOTIFY,

                                  LEGATTDB_PERM_NONE, 5),

               'D','a','t','a',' ','T','x',

 

          When working with this many values, it’s easier to weed out any discrepancies by zeroing all values out in between your read and write. For that reason, you’ll see a block of code within the transmission function doing just that.

 

  //clear out the previous values
  db_pdu.pdu[0x00] = 0;
  db_pdu.pdu[0x01] = 0;
  db_pdu.pdu[0x02] = 0;
  db_pdu.pdu[0x03] = 0;
  db_pdu.pdu[0x04] = 0;

 

          Additionally, we need to deal with the issue of sensor data exceeding one byte. If you try to put more than one byte of data into a one byte slot, you’ll be transmitting only the value that exceeds the one bye. For instance, one byte is equal to 256. If we try to fill it with the value 257, we’ll end up transmitting the value 1.

 

          With that said, you’ll find in the sample app a logic block within the transmit function that allows the data to carry over into the next byte if it exceeds one byte. This is, again, for the sake of readability and it isn’t necessary to dissect the logic. In your own apps, you can adapt the data transmission any way you’d like. And it's likely a better choice to just send changes in the data, which will likely never exceed a single byte.

 

          if (humidity < 255) {

            db_pdu.pdu[0x04] = humidity;

          }else if(humidity < 65535){

            db_pdu.pdu[0x03] = (humidity / 255);

            db_pdu.pdu[0x04] = humidity;

          }

 

---------------------------------------------------------SAMPLE FIRMWARE STEP-BY-STEP----------------------------------------------------

 

The following list is a combination of the preceding 2 posts and it will allow us to successfully transmit data to our LightBlue app:

 

    1. Power up the sensor
    2. Initialize the sensor
    3. On a loop:
      1. Start measurements of sensor
      2. Read data from sensor to a buffer
      3. Read the GATT characteristic
      4. Write the sensor buffer to the GATT characteristic
      5. Send the notification

 

Run the app on your WICED device and find it on your LightBlue app. Upon connection, you’ll receive a stream of notifications of the current temperature and humidity in hex format separated by a zeroed one byte margin for readability. Again, breathe on your board and watch the values sharply increase.

 

Being able to stream values to your LightBlue app is more than just the end goal. Rather, the ability to stream these values is an incredibly powerful tool in the design process. Consider the case that you’ve just designed your own board using a WICED BLE chip, but you don’t have the ability to run traces on the board. You now have the power to receive data from your chip and figure out where your code is failing.

 

Jacob W. Torres

 

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

 

           Transmitting BLE notifications is a straightforward process using the WICED APIs. The APIs are much more user friendly, however, with a conceptual understanding of the process. Before proceeding you should be comfortable with common terms in BLE as well as the very basics of the protocol. How do devices find one another? Which is the master and which is the slave? And which one advertises?

 

The question we’ll delve into today is: how do BLE devices exchange data? There is one key concept that must be understood to be able to instantiate BLE communication in your code: the GATT Database is the medium for tranceiving all data.

 

                In BLE, both the master (likely your phone) and the slave (likely your WICED device) are allowed to read or write to/from your GATT database. These reads and writes can follow any logical sequence of events:  the client can read data which is being continuously written by the slave, the client can write to the slave in order to tell the slave to write data to the GATT (the client will then perform a read), etc. These sequences are not fixed, and can be instantiated in any logical manner.

 

Additionally, the slave can send unrequested, unacknowledged “notifications” to the master, the master has the power to either ignore or listen to these notifications. This cuts out the complexities of reads and writes. The majority of BLE transmissions carried out are notifications. They are easy to use and very practical. For that reason, this post will demonstrate the execution of a BLE notification.

 

To send a notification, you must do two things: load the data into your GATT database and call the “notify” API to carry out the transmission at a hardware level.

 

The GATT database is not conceptual as it may have sounded up to this point—it’s to be clearly defined in every BLE app you ever create. The GATT database a hierarchy of services, characteristics, and descriptors. Some of these are mandatory—they will be identical in every app. The unique services and characteristics that you’ll be adding to your future apps are “vendor-specific.”

 

Within the GATT database there are services. Within services there are characteristics. Within characteristics there are descriptors. That’s all you need to know about the hierarchy within the GATT database. Characteristics are where the data is held, and where you’ll be writing in order to send data over BLE.

 

A service may have one or more characteristics. But a characteristic cannot exist outside of a service. For instance, although measuring someone’s heart rate only has one possible characteristic it requires a Heart Rate Service, and underneath it a Heart Rate Characteristic (the actual pulse rate). On the other hand, other services will require many characteristics which can all hold their own values. For example, a Vital Signs Service would have individual characteristics for pulse rate, blood pressure, respiratory rate, etc. For now, we will not discuss descriptors. They are only utilized for reads and writes to the GATT database (not notifications).

 

 

--------------------------------------------------------STEP-BY-STEP GUIDE TO FIRMWARE------------------------------------------------------

 

 

There are 5 distinct steps required to instantiate BLE notifications using the WICED API:

 

  1. Setup your GATT database
  2. Read the current value of your vendor-specific characteristic.
  3. Change that value.
  4. Write it back to your vendor-specific characteristic.
  5. Send the notification.

 

1.  Setting up the GATT database is the most difficult part of the process. The complexity of setting up your GATT database is dependent upon the complexity of your app. Contained in the sample firmware is likely the most simplified GATT database you will come across—aside from the mandatory inclusions, there is one service and one characteristic.

 

Each service must have a handle and a UUID. Each characteristic must have a handle and a handle value. These are unique values that must be defined by you. UUIDs can be generated randomly using an online generator.

 

In addition to these identifiers, each GATT definition must have defined permissions, property definitions, and lengths (number of bytes). The parameters used in the sample code are all you will need in order to send notifications. But there is a long list of these parameters available in How to Write WICED Smart Applications that guide you through the process of customizing your GATT database form the ground up. For further reading, I highly recommend reading about the GATT database parameters that are at your disposal in this document. 

 

                      const UINT8 ble_tx_gatt_database[]={

              /////////////////////mandatory for all apps//////////////////////////

              PRIMARY_SERVICE_UUID16 (0x0001, UUID_SERVICE_GATT),

 

 

              PRIMARY_SERVICE_UUID16 (0x0014, UUID_SERVICE_GAP),

 

 

              CHARACTERISTIC_UUID16 (0x0015, 0x0016, UUID_CHARACTERISTIC_DEVICE_NAME,

                                    LEGATTDB_CHAR_PROP_READ,

                                    LEGATTDB_PERM_READABLE, 16),

                'B','L','E',' ','D','a','t','a',' ','T','x',0x00,0x00,0x00,0x00,0x00,

 

 

              CHARACTERISTIC_UUID16 (0x0017, 0x0018, UUID_CHARACTERISTIC_APPEARANCE,

                                    LEGATTDB_CHAR_PROP_READ,

                                    LEGATTDB_PERM_READABLE, 2),

                BIT16_TO_8(APPEARANCE_GENERIC_TAG),

              /////////////////////////////////////////////////////////////////////

 

              ////////////////vendor specific, optional, customize///////////////

              PRIMARY_SERVICE_UUID128 (HANDLE_BLE_TX_SERVICE_UUID,

                                      UUID_BLE_TX_SERVICE),

 

              CHARACTERISTIC_UUID128 (0x0029, HANDLE_BLE_TX_VALUE_NOTIFY,

                                      UUID_BLE_TX_CHARACTERISTIC_NOTIFY,

                                      LEGATTDB_CHAR_PROP_NOTIFY,

                                      LEGATTDB_PERM_NONE, 1),

                '1','2','3','4','5','6','7',

              ////////////////////////////////////////////////////////////////////

          };

 

2.  Reading the current value of the characteristic you wish to write to is as simple as calling an API. First, we must instantiate a variable of type BLEPROFILE_DB_PDU, then call on the appropriate API to read. This API requires two parameters: the handle of the value you wish to read, and a pointer to the newly created variable.

 

                        BLEPROFILE_DB_PDU db_pdu;

            bleprofile_ReadHandle(HANDLE_BLE_TX_VALUE_NOTIFY, &db_pdu);

 

3.  In order to change the transmitted value, we change the "pdu" component of the db_pdu struct (.pdu[]) equal to the data we wish to send. In this case a constant:

 

            db_pdu.pdu[0] = my_data;

 

4.  Again, all we must do is call an API to write the changed value back to the characteristic, using the same parameters as the read:

 

            bleprofile_WriteHandle(HANDLE_BLE_TX_VALUE_NOTIFY, &db_pdu);

 

5. Lastly, we call the notify API to carry out the transmission at the hardware level. Note the parameters and emulate in your own code.

 

            bleprofile_sendNotification(HANDLE_BLE_TX_VALUE_NOTIFY,

                                      (UINT8 *)db_pdu.pdu, db_pdu.len);

 

                For the most basic BLE notification, there are no further steps that you need to take. In the sample app, we load the notification with an arbitrary constant and send it to out. But this very byte can be loaded with any data of our choosing: sensor data, status, timing, etc. Run the test app along with your LightBlue App and watch the constant value be received every 500ms.

 

Jacob W. Torres

 

 

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

 

 

    We won’t get into the fine details of the I2C protocol. Here, we will show how to execute I2C reads and writes using the WICED Smart platform and API. Keep in mind that what’s contained in this blog only applies to other chips at an abstract level. The specific API and drivers we have are for WICED Devices.

 

    What is a driver? Without an understanding of I2C you may look at an I2C driver in wonder. The driver is a set of functions that calls on the I2C API (the API is what is actually executing the I2C protocol at a hardware level) in a device-specific manner to make the sensor serve its purpose. Every sensor has its own driver and therefore requires that a different sequence/different register addresses/different I2C addresses be used. When creating your own apps you will never interact with the I2C API, but rather the driver for the specific sensor with which you wish to interact.

 

    The drivers necessary for the Tag4 are attached to this post. But let’s consider the other case: you get your hands on an I2C sensor that isn’t attached to your Tag4 device and you want to attach it. That’s for a separate, future project entirely, but we will, indeed, enter the realm of writing our own drivers for I2C devices.

 

    There are basic principles to understand before attempting to use an I2C device. It’s highly advised that you gain a general understanding of the protocol before proceeding (understand the use of addresses versus hardware chip select lines like on SPI, a different serial protocol).

 

    In all the research you’ve done at this point, you likely understand what a read and write sequence looks like. Conceptually, however, how do we interact with a sensor?

 

    • Writing to an I2C Register
      • In the sensor’s data sheet you will find a series of command registers. These command registers are to be written to in order to change the characteristics of the sensor. This is what your initialization will consist of (see below).

 

    • Reading Data from an I2C Device
      • In order to gather data from an I2C sensor, there are generally multiple steps taken. In order to read sensor data, the device must be written to, told to fill its data register with data, then that register must be read from. Sometimes, a third step is necessary: you may need to check the status of the data prior to reading (by reading a status register) and not perform the reading until the data is available. This is sometimes necessary because prematurely reading data will destroy it.

 

Fortunately, prewritten drivers do most of the tough work for you. Nonetheless, it’s necessary to understand for future I2C projects and debugging.

 

 

-------------------------------------------------STEP-BY-STEP GUIDE TO SAMPLE FIRMWARE-----------------------------------------------

 

 

With all that said, there are four steps that you will see in the attached test code that are necessary to accomplish the task at hand:

      1. We must apply power to the sensor.
      2. Then, we must initialize the sensor.
      3. Third, we tell the sensor to fill its data registers with the information we need.
      4. Lastly, we read the data register.

 

1.  On the Tag4 board the sensors are powered by a BJT that that is controlled by GPIO 2. In order to apply power to the sensors, in our create function we put GPIO 2 low (PNP BJT) in order to apply power to the sensors. Additionally, the sensor switch block must be physically switched on (SW 9).

 

gpio_configurePin(0, 2, GPIO_OUTPUT_ENABLE | GPIO_INPUT_DISABLE, 0);
gpio_setPinOutput(0, 2, 0);

 

2.  To initialize the sensor, we have a prewritten function in the test code that initializes the sensors that will suit most of your needs. In this function we activate the sensor, set the ODR rate (sample rate, linearly related to power consumption), set average values, and finally, we enable the BDU feature. Without ever looking into the driver, however, we can alter these characteristics in order to fit app-specific needs.

 

   

                        void init_hts221(void){

                if(HTS221_Activate() == HTS221_OK)

                    ble_trace0("HTS221_Activate Successful");

                else

                    ble_trace0("HTS221_Activate Failed.");

 

                if(HTS221_Set_Odr(HTS221_ODR_7HZ) == HTS221_OK)

                    ble_trace0("HTS221_Set_Odr Successful");

                else

                    ble_trace0("HTS221_Set_Odr Failed.");

 

                if(HTS221_Set_AvgHT(HTS221_AVGH_8, HTS221_AVGT_4) == HTS221_OK)

                    ble_trace0("HTS221_Set_AvgHT Successful");

                else

                    ble_trace0("HTS221_Set_AvgHT failed");

 

                if(HTS221_Set_BduMode(HTS221_ENABLE) == HTS221_OK)

                    ble_trace0("HTS221_Set_BduMode Successful");

                else

                    ble_trace0("HTS221_Set_BduMode failed");

            }

 

 

3.  Given that we’re working with one stop measurements it is necessary to tell the sensor to start its one stop measurement. This is compared to instantiating a FIFO which will constantly stream data. The code for starting the measurement is paired with that of step 4..

 

4.  Lastly we read the data register. This is a call to a function in the driver, into which we pass two pointers for the data to be inserted. We'll then use this variable as the buffer of our data to accomplish anything we want: printing their value, transmitting it, etc.

 

                          if(HTS221_StartOneShotMeasurement() == HTS221_OK){

 

                  if(HTS221_Get_Measurement(&humidity, &temperature) == HTS221_OK)

                      ble_trace2("Humi*10=%6d, Temp*10=%6d", humidity, temperature);

 

              }

 

 

Steps 1 and 2 are to be executed once in your create function. Steps 3 and 4 will be done continuously, in a loop (in our test app). When we work with interrupts we will be able to trigger a read on an interrupt. Alternatively, we may consider the case of power saving. In the test app, we start the sensor and never stop it. But if every micro-amp counts for your application, you may de-initialize the sensor and put P2 high, then reinitialize when you need the sensor again.

 

              void hts221_deinitialize ( void ) {

 

            if(HTS221_DeActivate() == HTS221_OK)

                ble_trace0("HTS221_DeActivate Successful");

            else

                ble_trace0("HTS221_DeActivate Failed.");

 

        }

 

Run traces on the attached test code. The values will stream across your terminal. Breathe on your board and watch the values for humidity and temperature rise.

 

Jacob W Torres

 

 

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

******************************************************************************************************

Tag 4 Specific Information

******************************************************************************************************

 

 

 

******************************************************************************************************

Simple Projects for All WICED Smart Platforms

******************************************************************************************************

 

 

 

******************************************************************************************************

Setting Up the WICED Smart Platform

******************************************************************************************************

Learn to Navigate the Forum

  • Learn to find your way around the WICED Sense forum.
  • When using the search bar, be sure to use "click here to only show results for Bluetooth Forums" when it appears

 

Download the SDK

  • Download the most recent release for your operating system here: WICED Smart Docs & Downloads
  • You may run into problems with Java, see here: Java Issues....
  • You may need to update your USB drivers as well: Virtual COM Port Drivers
  • The device driver may not have downloaded when you plugged in your WICED Device (pops up in bottom right corner if failed). If this is the case, go to Device Manager>Other Devices. Find BOTH devices associated with your board, double click one, click "Look for Drivers," click "Next" and the download should complete shortly thereafter. Then do this for the second device.

 

Download LightBlue

  • Allows your phone to be used as a test device for your BLE apps
  • Download in your mobile device’s app store

 

Learn to Use the SDK

  • Refer to the WICED Smart Quick Start Guide (SDK 2.x and TAG4 Board)
    • Download your first test App. "Heart Rate Monitor" feeds fake data notifications.
    • Connect to the device on LightBlue, listen to its notifications
  • Explore the SDK
  • Explore the API library
    • This is a highly useful tool to have in your arsenal.
    • Normally found in the SDK (WICED-Smart-SDK>Doc>API)
    • But, you may have trouble accessing it that way.
      • Alternate: right-click the link>"Open With">"Web Browser"
    • Get to know the APIs at your disposal through this library
    • When you begin writing your own apps, you will want to heavily utilize this resource.

 

 

Jacob W. Torres

JacobT_81

kwang

SOTAFU for Android and iOS

Posted by kwang May 27, 2015
RevisionChange DescriptionDate
1.0Initial Draft - VR09/30/14 - 8:45PM
2.0Android and iOS Implementation05/27/15 - 5:00PM

 

 

The SDK 2.1.1 provides a Secure OTA Firmware update.RSA.JPG

 

Wiced smart memory partition

 

Address.JPG

 

Verification.JPG

 

 

 

Flowchart of the SOTAFU

 

 

Flowchart.JPG

 

FOR ANDROID

 

Download Sample App )for Side-loading onto Android Device)

Version 1.00  for Android 4.3 MR2  Jellybean or higher (Android API level 18 or higher)

Installation instructions: (apk file and source code included in post)

     1.  If you previously installed WicedSmartOta.apk, please make sure to remove it

          adb uninstall com.broadcom.app.wicedsmart.ota

     2.   Download the .apk file to a computer with adb installed

     3.   Connect your android device to your computer

     4.   From command line, type "adb install -r WicedSmartOta.apk"

 

How to Use the OTA Sample Application

     1.  Prerequisites for OTA Upgrade

         To perform OTA update the following conditions must be met

          a. The update firmware must be signed with the same private/public key that the firmware

               running in the target WICED SMART tag

          b. The update firmware must have the same ApplicationId as the firmware running in the

               target WICED SMART tag

          c. The update firmware's MajorVersionNumber must be equal or greater than the

              MajorVersionNumber of the firmware running in the target WICED SMART tag

           If any of these preconditions are not satisfied, OTA upgrade will fail.

 

     2.  Updating the WICED SMART tag firmware via OTA

          The WICED SMART OTA App provides an OTA service to allow one to upgrade the

          firmware of a connected WICED SMART tag.  To use the OTA firmware update service:

          a.  Make a local directory on the phone/tablet: /sdcard/broadcom/wicedsmart

               adb shell mkdir -p /sdcard/broadcom/wicedmart

          b.  Copy the wiced sense signed binary file to the /sdcard/broadcom/wicedsmart folder,

               making sure the firmware has the extension ota.bin.signed

               adb push XXXXXXXXX.ota.bin.signed /sdcard/broadcom/wicedsmart/

          c.  Turn on the WICED SMART tag

          d.  Using the WICED SMART OTA application, Search for the WICED SMART tag and

               select that device

          e.  Connect to the tag by clicking on the connect button in the action bar.

          f.   Verify the tag's running firmware version info by connecting to the tag and viewing the

               firmware's version info from the "Get sensor Info": menu option. This should upgrade

               the background of the application with the firmware info

1.png5.png

          g.  Go to the Upper right corner of the menu bar, and select "Check for software updates"

          h.  If you have more than one version of the firmware software in the

               /sdcard/broadcom/wicedsense directory, you will be prompted to select the file to

               upload to the WICED SMART tag. Otherwise, the OTA update service will automatically

               begin uploading the single firmware file embedded in the sample WICED SMART OTA

               App. (Bottom Left Image)

3.png4.png

          i.   Wait for the OTA Service to finish uplaoding and verify the firmware.

               (Top Right Image)

          j.   Close and reopen the WICED SMART OTA app

          k.  Reconnect to the WICED SMART tag and get the running firmware's version info to

               verify the firmware has been updated

 

 

OTA Implementation Instructions

 

     1. The OTA code is an included set of Objective C APIs and optional UI components that can

          be included into an app.

     2. The OTA code resides in the folder WicedSmartOtaHelper

          •    OtaManager manages the OTA upgrade process

          •    OtaCallback is a delegate object you will implement and register with OtaManager to

               receive "callback  events" that give the state/status of the OTA upgrade.

     3. Typical use case for implementing OTA Update using the OtaManager class

               •    Create an instance of OtaManager.

               •    Create an instance of your class that implements the delegate OtaCallback.

               •    Call OtaManager's addCallback method to register your callback.

               •    Read the OTA binary and obtain a NSData byte array for your binary.

               •    Call the OtaManager startUpdate method, passing it the byte array - Implement the

                    OtaCallback methods to receive callback events on the OTA transfer state.

               •    Call the OtaManager about method to abort the upgrade if needed.

 

The above basic API code will allow a user to design and implement an app with custom UI components to manage OTA upgrades.  However, a default UI implementation is provided.

OtaUIHelper provides a default UI wrapper around OtaManager.

 

The basic use case for OtaUIHelper is:

     •    Add the OTA binary that is signed with your private key into the folder fwupdate with

          the name ****.ota.bin.signed

     •    Modify the OtaFirmwareUpdateInfo.m configuration class that is in the fwupdate folder,

          specifying the name of your binary.

     •    Create an instance of OtaUiHelper

     •    Implement an instance of OtaHelperDelegate to receive callback events about when the

          OTA process starts, stops, or terminates unexpectedly.

     •    Register the OtaHelperDelegate instance with OtaUiHelper by setting its delegate

          property.

     •    Call startUpdate API method.

 

 

FOR iOS (iOS 7 or higher)

 

OTA Implementation Instructions

 

(Source code is attached in post)

     1. The OTA code is an included set of Objective C APIs and optional UI components that

          can be included into an app.

     2. The OTA code resides in the folder WicedSmartOtaHelper

          •    OtaManager manages the OTA upgrade process

          •    OtaCallback is a delegate object you will implement and register with OtaManager to

               receive "callback events" that give the state/status of the OTA upgrade.

     3. Typical use case for implementing OTA Update using the OtaManager class

          •    Create an instance of OtaManager.

          •    Create an instance of your class that implements the delegate OtaCallback.

          •    Call OtaManager's addCallback method to register your callback.

          •    Read the OTA binary and obtain a NSData byte array for your binary.

          •    Call the OtaManager startUpdate method, passing it the byte array - Implement the

               OtaCallback methods to receive callback events on the OTA transfer state.

          •    Call the OtaManager about method to abort the upgrade if needed.

The above basic API code will allow a user to design and implement an app with custom UI components to manage OTA upgrades.  However, a default UI implementation is provided.

OtaUIHelper provides a default UI wrapper around OtaManager.

The basic use case for OtaUIHelper is:

     •    Add the OTA binary that is signed with your private key into the folder fwupdate with the

          name ****.ota.bin.signed

     •    Modify the OtaFirmwareUpdateInfo.m configuration class that is in the fwupdate folder,

          specifying the name of your binary.

     •    Create an instance of OtaUiHelper

     •    Implement an instance of OtaHelperDelegate to receive callback events about when the

          OTA process starts, stops, or terminates unexpectedly.

     •    Register the OtaHelperDelegate instance with OtaUiHelper by setting its delegate

          property.

     •    Call startUpdate API method.

 

 

Thanks,

 

JT

In this demo, we will see how to load the SmartBridge web application and connect with the WICED Sense kit to display sensor data.

 

  1. Downloads and Installations
    • Download the es-WiFi demo software and drivers from:

                    www.inventeksys.com/wp-content/uploads/Inventek_Systems_eS-WiFiDemo_v1.4_b2.zip

                         **** DO NOT CHANGE THE LOCATION OF THE WIFI DEMO SOFTWARE ON YOUR PC FROM THE ORIGINAL LOCATION GIVEN                 

 

                    Install it in the platforms folder:  ...\WICED\WICED-SDK-3.1.2\WICED-SDK\platforms

    • Upon installation, you should see the patches in the platforms folder:

                    ISM_Platforms.PNG

 

     2. Running the ISM GUI

                    Note: If an error or problem occurs for any step throughout the connection process, it is important to unplug the ISM340USB stick, plug it back in and start from the beginning of this tutorial.

    • In order to run the ISM GUI go to the following folder: ..\Inventek Systems\eS-WiFi\demo and open the es-WiFI.application
    • plugin the ISM340 USB stick into the PC and identify which COMPORT it is
    • In the es-WiFi demo GUI, go to Menu > Install Drivers
    • Once installation is complete, you should see this screen:

                                  

 

    • Go to device manager, click on the correct COM port and change the following settings
      • Baud Rate/BPS: 115200
      • Parity: None
      • Data Width: 8
      • Stop Bits: 1
      • Flow Control: None

 

    • We shall now open the Com Ports: To do so go to Setup > Serial Port > Configure/Open
    • You should see the following screen:

 

              

 

    • Verify that the correct settings are in place as listed above and press OK to open the COM port.

 

     3. Setting up the SmartBridge Web Application

               Note***: Before we begin, it is important to note that every command has to be typed into the command line box. After you type in a command and press send, it will always take you to the main window. It is important to go navigate back to the command line to ensure a much smoother process.

 

    • Type in your SSID into the command line box and press send. Once you press send, the program will ask you if the SSID listed above is correct, type in and enter "y" or "n' accordingly.
    • Once past this step, type in the correct password. Once again it will ask you if the password that shows on the screen is correct. Give the appropriate response.
    • Once your password is entered, enter your security type and press "y". It will automatically generate an IPv4 address for the SmartBridge web application.

                   

    • Copy and Paste the given IPv4 address into the internet browser of your choosing. You have now connected to the BT SmartBridge application

 

     4. Connecting to the WICED SENSE

    • We shall connect the ISM-43340 USB stick with the WICED Sense Kit
    • We have programmed wiced_sense.c onto the Kit to display all sensor information
    • Wake up the WICED Sense Kit and press Rescan on the web application
    • You should see the name: WICED Sense Kit along with an address. Connect with the Kit by pressing the "connect" button right next to the address of the Kit
    • Once connected, the WICED Sense Kit will show up on the Connection Pairings List. You have now connected the ISM340 with the WICED Sense Kit.

              

 

 

    • In order to view the GATT profile, we will press the "Details" button. Once pressed,  the screen should look like this:

                   

 

 

We have now completed the Inventek ISM340 SmartBridge Application Demo. For further questions, please refer to the community forums.

This blog is designed to demonstrate how to add and remove peripheral devices from the White List using hello_sensor and hello_client.

We will use 2 TAG03 boards, but you can use 2 or more.

 

We will show you how to clear the white list and how to enable the white list and add a mac address to it as well as have advertisements sent only to the device which has been added to the white list.

 

 

1. Update hello_sensor

     Attached is the modified hello_sensor.c file that should be downloaded to replace the existing hello_sensor.c file.

 

2. Change the makefile name of hello_sensor and download it. The new makefile should be as follows:

  hello_sensor-BCM920736TAG_Q32 BT_DEVICE_ADDRESS=112233445567 UART=COMxx download

 

3. Change the makefile name of hello_client and download it. The new makefile should be as follows:

hello_client-BCM920736TAG_Q32 BT_DEVICE_ADDRESS=112233445566 UART=COMxx download

 

** Note: xx is the COM port number designated to your specific TAG03 board.

 

4. Open HCI traces for the board with hello_sensor programmed on it (board 'B') to observe the white list enable/disable and start/stop advertisement. (For more information on how to use traces, please check the Quick Start Guide)

 

5. Modify the client_addr array in the hello_sensor.c file to contain the mac address of hello_client as follows:

 

     ***NOTE: The client address (board B) should be the first address in the array.

 

6.  Hold SW1 on the hello_client board (board 'A') for 6 seconds. While holding SW1 on board 'A', press SW1 on board 'B'. The following trace should pop up on the console, with the mac address of the client listed:

We can see that board 'B' is added to the white list for board 'A' and can now send notifications,etc.

 

Here are the steps required to delete an address from the white list:

 

  1. change the address on hello_client to be random:

          hello_client-BCM920736TAG_Q32 BT_DEVICE_ADDRESS=random UART=COMxx download

 

    2. Open HCI traces, and hold SW1 on hello_client board (board 'A') for 6 seconds. While holding SW1 on board 'A', press SW1 on board 'B'. You will see that board 'B' does not connect to board 'A'. This is  because the white list of board 'A' does not include board 'B'. As a result, there will be no exchange of advertisements with board 'B'.

 

 

 

Fore more information on how to proceed, here is a chart:

 

This BLOG is a short introduction for configuring the TAG3 board for use with the Serial FLASH.

This information is taken from our TAG3 document Manual :  The specified item was not found. and our Quick Start Guide The specified item was not found.

1.  The TAG3 board contains a Serial FLASH device and can be configured with a few resistor modifications and additions:

See the TAG3 Board below:

 

TAG3Board_SFLASH.JPG

 

2.  TAG3 Board Assembly displaying the resistor installation/modifications for the on board Serial FLASH:

 

3.  The table below defines the resistors to configure the Serial FLASH:

 

4.  You will need to place the SW4 switches 5,6,7,8 in the OFF position (They are actually show in the ON Position in this photo):

 

 

5.  In the SDK you will need to modify your Make Target to include NV=SFLASH:

 

Note: In this case we have used COM Port 21 as observed in our Windows Device Manager:

 

 

 

5.  Using the Recovery Procedure from the The specified item was not found. document, your recovering console message should look like the following:

 

 

 

A few extra notes about Serial FLASH:

 

 

You will need to use the same Macronix Serial Flash that is supported by the ROM and ships on the TAG3 board.  Please see the schematic snippet below:

 

 

http://community.broadcom.com/servlet/JiveServlet/showImage/2-5581-2069/Macronix.png

 

The Macronix MX25U4033 device works as well if you needed a second option.

 

Please see the notes below:

 

MX25U4033: http://www.macronix.com/en-us/Product/Pages/ProductDetail.aspx?PartNo=MX25U4033E (good for new designs)

 

MX25U4035: http://www.macronix.com/en-us/Product/Pages/ProductDetail.aspx?PartNo=MX25U4035 (not recommended for new designs)

 

Regarding the two different Flash PNs, here’s a document from the Macronix website that compares the two: http://www.macronix.com/Lists/ApplicationNote/Attachments/669/AN126V1_MX25U4035%20to%204033E.pdf

 

We will continue to update this BLOG as questions arise.

 

 

 

Thanks

JT

MichaelF_56

BCM2073XS GPIO Basics

Posted by MichaelF_56 Moderator Dec 17, 2014

The BCM2073x chip (SoC) has 40 logical GPIOs (P0-P39).

 

The GPIOs themselves are broken out into three separate ports (meaningful when you start programming):

 

• P0 through P15 on port0

• P16 through P31 on port1

• P32 through P39 on port2

 

The 32 pin package (i.e. the SoC - BCM20736 and BCM20737 *without* the S) only brings out 14 of the 40 logical GPIOs. The System in Package/SIP (the BCM20736S and BCM20737S modules) follows the SoC closely with regards to which pins are brought out (but there is a slight difference) and these are what you see in the SIP module datasheets.

 

Since the 32 pin package (SoC) and the modules are pin-limited, some of the logical GPIOs within the SoC are multi-bonded before bringing them out on the balls on the chip.

 

For the 32 pin package, the following pins are bonded in this manner:

  • P8 and P33 (only one of two is available)
  • P11 and P27 (only one of two is available)
  • P12 and P26 (only one of two is available)
  • P13 and P28 (only one of two is available)
  • P14 and P38 (only one of two is available)

 

Very Important Note: The SOC packaged part described above is not used for the SIP module. The SIP uses the raw die and wirebonds it differently than the DFN part, so the IOs described above for the SoC are not bonded together from the die - they are bonded together on the DFN wirebond package.

 

Always refer to the BCM20737S Bluetooth Low Energy SiP Module Technical Reference for the bonding/alternate function information relevant to the SIP modules, not the CYW20737 SOC Data Sheet.


When leveraging the WICED™ Smart Hardware Interfaces for your development, you will run across several GPIO mapping tables in the document that look like this one:

gpio1.png

Note here that you can use only one of the GPIOs (noted in black) from each of the vertical rows above.  This is what is referenced in the WICED Smart Hardware Interfaces as a "group" (all signals must be selected from the same group, which is essentially the table).

 

All options may not be available in the package used within the SIP module (shown in red). Combinations shown in red text are also not generally available on the BCM20732 TAG. Additional options may be unavailable if they are being used for the peripheral UART interface.

 

All GPIOs support programmable pull-up and pull-down resistors, along with a 2 mA drive strength except P26, P27, and P28, which provide a 16 mA drive strength at 3.3V supply (this will change as the supply drops and the GPIO pins will sink less current).

 

The GPIOs are all capable of waking the device from sleep or deep sleep and the application can configure interrupts (both/either edges, level), pull-up/pull-down High-Z, etc.

 

The following GPIOs are available on the BCM2073XS based SIP Modules (remember, only 14 are brought out on the SIP module):

 

  • P8/P33 (Dual bonded, only one of two is available)
    Change per information received on 4/28/15: our packaging facility confirmed that P8 and P33 are both available and that on the SIP they are not dual-bonded
  • P13/P28 (Dual bonded, only one of two is available)
  • P14/P38 (Dual bonded, only one of two is available)
  • P12/P26 (Dual bonded, only one of two is available)
    Change per information received on 4/28/15: our packaging facility confirmed that P12 and P26 are both available and that on the SIP they are not dual-bonded
    - P12 if not used as P26 or external 32KHz LPO; If used as 32KHz LPO, then P12 and P26 are unavailable
    - If external 32KHz OSC is used then P12 is not available, but P26 is available
  • P11/P27 (Dual bonded, only one of two is available)
    -P11 if not used as P27 or external 32KHz LPO; If used as 32KHz LPO, then P11 and P27 are unavailable
    - If external 32KHz OSC is used then P11 is not available, but P27 is available

 

For unused dual bonded pins, the unused GPIO should be input/output disabled (especially when it is an input).

 

gpio1.png

gpio2.png

gpio3.png

gpio4.png

gpio5.png

gpio6.png

gpio7.png

 

From the perspective of writing software against the GPIO mappings defined above, it's important to keep in mind that the GPIO is physically mapped to a BCM2073XS device within the platform.h file which is custom to the TAG development board by default.

 

However, this mapping in platform.h can be reconfigured for a custom design.

 

The values in platform.h then map to definitions and function prototypes in bleprofile.h

 

Note that the specific values in the bleprofile.h bitmasks themselves are not intended to be exposed as the code beneath these bitmasks is proprietary and cannot be released for reasons outside the scope of this discussion.

 

In addition to reconfiguring the mappings of your custom board within the bleprofile.h, GPIO can also be assigned within BLE_PROFILE_GPIO_CFG within the .c file for each application. This is also where you allocate/initialize the GPIO within your application.  The bleprofile_xxx() routines are then how you use/access what you have configured above.

 

With this said, I realize there is some ambiguity in this message as we have documents like WICED™ Smart Hardware Interfaces which clearly states that the BCM2073X (note that this guide was written for the SoC, then modified slightly for the SIP module) includes two sets of APIs that are available for the application: the low-level driver API and the high-level profile API.

 

So yes, the Low Level API is there and in some cases ok to use, but we are not consistent in exposing everything a developer needs to actually use it effectively on a consistent basis.

 

Hopefully you guys find this helpful.  I know many of you have tidbits to add, so feel free to comment (please stay on topic). I would love to see some examples and code snippets showing usage of the bleprofile_xxx() routines.

jota_1939431

I2C Discussion

Posted by jota_1939431 Oct 27, 2014
RevisionDescriptionDate
1.0I2C Description10/27/14

 

The I2C topics seem to be a bit confusing.

I am creating this Blog to address these concerns.

 

I will post a video shortly that will thru a Code Walk Thru.

 

NOTE:

There is a known issue with i2cm_* functions.

You must use cfa_* functions instead.

 

 

i2cm_* can only be used when patch enable_spiff1_i2c_interop.a is used *and* NV is serial flash on SPI1

 

Here are miscellaneous notes that have collected regarding the I2C Issues:

 

Both SCL and SDA should be high before I2C communication begins.

 

SPIFFY1 is shared with I2C, which is already being used to talk to the EEPROM on the module.

 

 

SPI-flash and I2C interfaces concurrent:

 

 

We don’t have the drive strength once to drive the I2C line hard enough with a total of 4 slaves on the bus.

 

 

How the SDA pin is sampled during boot by the firmware and how the I2C pins behave:

  • Connecting SDA to Vdd/Vio to recover is probably a bad idea
  • SCL and SDA are both open-drain
  • The pull-ups pull the signal high while the HW drives it low
  • It never drives high, but floats the output pad leaving the pull-up to pull the line high
  • If you put a scope to either of these lines on the board when the FW accesses these, high to low transitions will be very sharp while low to high transitions will be pretty slow due to the intrinsic RC
  • If you connect SCL/SDA to Vdd, then when the HW block drives SDA low, there will be a direct short (though momentary) between Vdd and GND - Not good
  • This will happen pretty early during boot because the ROM always uses 0xA0 as the slave address of the EEPROM and you can see that there are repeated 0s in this sequence (and the shorts) which could do bad things to the supply or the chip
  • Shorting to GND on the other hand, is safer because that is what happens when there is a 0 bit on the bus and there is a 10K pull-up which will limit the current to something within the max ratings of all components on this line

 

How to decrease the clock speed during programming (and for subsequent accesses to the EEPROM), because the faster clock speed seems to be causing another i2c device to lock up:

 

 

See i2cm.h, i2cm_setSpeed(). Use I2CM_SPEED_* from this header.

 

If you use cfa_* API that is used by the i2c_temperature_sensor sample, you cannot change the I2C bus speed (defaults to 400KHz). You can use the corresponding API in i2cm.h to read/write the same data and also change speed if required

 

 

I2C and P_UART Dependency:

  • PUART and I2C don't have any dependency. You can use both at the same time. SPI2 and PUART however do have some restrictions, see the datasheet or the HW interfaces document (in short - PUART RX and SI2 have to be on the same GPO bank).
  • I2C and SPI1 share GPIOs. With SDK 2.1 and above, there is an optional patch with which you can use I2C when SPI1 is used for NV storage (serial flash). But the other way where you want to use SPI1 as an SPI master when using I2C EPROM slave is not possible.

 

 

 

To use it, you just have to include the patch and use the API in i2cm.h:

 

# Add to application’s makefile.mk:

APP_PATCHES_AND_LIBS += enable_spiffy1_i2c_interop.a

 

The in application, #include “i2cm.h”  and use the I2C API in this header to access the I2C slaves. No changes to the way you access NV (using bleprofile_*)

 

The cfa.h interface is where most people failed in their code

 

Example Code:

// Reads 16 bits from the given register address in LM73.

// \param register_address The address to the register to read.

// \param data INOUT Pointer to a INT16 into which the data is to be read, valid only if return value is 1.

// \return 1 if successful, 0 on failure.

UINT8 temperature_sensor_read_16_bit_register(UINT8 register_address, INT16* data)

{

    UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_read_bytes_to_write[1];

    UINT8 reg_bytes_to_read[2];

    reg_read_bytes_to_write[0] = register_address;

    // Do a combo write then read operation

    read_status = i2cm_comboRead(reg_bytes_to_read, sizeof(reg_bytes_to_read), reg_read_bytes_to_write,

                                                        sizeof(reg_read_bytes_to_write), LM73_SLAVE_ADDR);

 

    switch(read_status)

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

                // There is already a pending transaction.

            break;

 

        case I2CM_SUCCESS:

            // The read was successful.

            *data = (INT16)(reg_bytes_to_read[1] | reg_bytes_to_read[0] << 8);

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

 

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

            break;

    }

    return return_value;

}

 

// Writes the given value ino the given 16 bit register.

// \param register_address The address of the register to write to.

// \param data The data to write.

// \return 1 on success; else 0.

UINT8 temperature_sensor_write_16_bit_register(UINT8 register_address, INT16 data)

{

    UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_bytes_to_write[3];

    reg_bytes_to_write[0] = register_address;

    reg_bytes_to_write[1] = (data >> 8) & 0xFF;

    reg_bytes_to_write[2] = data & 0xFF;

    read_status = i2cm_write(reg_bytes_to_write, sizeof(reg_bytes_to_write), LM73_SLAVE_ADDR);

 

    switch(read_status)

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

           // There is already a pending transaction.

 

            break;

 

        case I2CM_SUCCESS:

            // The read was successful.

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

            break;

    }

    return return_value;

}

 

// Reads given register by first writing the pointer register

// then reading the register value. Leaves the pointer register as is when leaving

// \param register_address The register to read from

// \param data INOUT Pointer to a buffer into which to read. Valid only if the return value is 1

// \return 1 on success; else 0.

 

UINT8 temperature_sensor_read_8_bit_register(UINT8 register_address, UINT8* data)

{

                UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_bytes_to_read[1];

    // Do a combo write then read operation

    read_status = i2cm_comboRead(reg_bytes_to_read, sizeof(reg_bytes_to_read), &register_address,

                                                        sizeof(register_address), LM73_SLAVE_ADDR);

    switch(read_status)

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

            break;

 

        case I2CM_SUCCESS:

            // The read was successful.

            *data = reg_bytes_to_read[0];

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

 

            break;

    }

    return return_value;

 

}

// Writes the given value to the given register by first writing the pointer register

// then writing the value. Leaves the pointer register as is when leaving.

// \param register_address The address of the register to write to.

// \param data The data to write to the register.

// \return 1 on success; else 0.

 

UINT8 temperature_sensor_write_8_bit_register(UINT8 register_address, UINT8 data)

{

    UINT8 read_status;

    UINT8 return_value = 0;

    UINT8 reg_data_bytes[2];

    reg_data_bytes[0]= register_address;

    reg_data_bytes[1] = data;

 

    read_status = i2cm_write(reg_data_bytes, sizeof(reg_data_bytes), LM73_SLAVE_ADDR);

    switch(read_status)

 

    {

        case I2CM_BUSY:

            // Transaction did not go through. ERROR. Handle this case.

            break;

 

        case I2CM_SUCCESS:

            // The read was successful.

            return_value = 1;

            break;

 

        case I2CM_OP_FAILED:

            // No slave device with this address exists on the I2C bus. ERROR. Handle this.

        default:

            break;

    }

    return return_value;

}

 

 

 

RevisionChange DescriptionDate
1.0Initial - 15 minute video10/08/14

 

 

Michael L. takes us through a Schematic Review of the iBCN BCM20737 Reference Design.

 

Thank you Michael.

 

WICED Smart Documents & Downloads

 

The schematic is located:

iBeacon BCM20737 Reference Design PDF Schematic (SOC)

 

The Gerbers are listed here:

iBeacon BCM20737 Reference Design Gerber Files (SOC)

 

He discusses:

  1. The Baseband section of the BCM20737
  2. Recovery Process
  3. Common mistakes he has seen from designers
  4. Decoupling Caps for the Pins and RF section

 

 

 

Let us know if you have any questions

Thank you

 

JT

Filter Blog

By date:
By tag: