The maximum LL PDU (Packet Data Unit) for BLE 4.1 is 27 Bytes. In these 27 Bytes, the actual data that is transferred as a GATT Write or Notification can be upto 20 bytes, excluding the L2CAP header, Data PDU Header and Attribute Operation Code. If the link is encrypted, the LL PDU will additionally have a 4 Byte MIC (Message Integrity Check), there by making the LL PDU as 31 Bytes.
The LL Packet comprises of LL PDU (31 Bytes) + PDU Header (2 Bytes) Header (1 Bytes) + Access Address (4 Bytes) + Cyclic Redundancy Check (3 Bytes)
= 41 Bytes
= 41 * 8 Bits
= 328 Bits
The propagation time of each bit is 1uS. So for 328 Bits it is 328 uS. After each packet is sent, an additional 80 uS is spent for acknowledgement. Also, there is T_IFS, (Interframe time between a packet and acknowledgement and also between acknowledgement and next packet)
So time taken for 1 packet to be sent is:
328uS (actual data) + 150 uS (T_IFS) + 80 uS + 150 uS (T_IFS) = 708 uS
The number of packets per connection interval = Connection interval / 708 uS.
If the connection interval is 7.5 mS, approximately, 10 packets can be sent.
The relation between the throughput and the connection interval is not so straight forward. As discussed in the previous interaction the time taken for sending 20 bytes is 708 uS.
Now let us discuss this with 3 cases of connection interval:
1) Assume that connection interval is 7.5 mS.
Number of packets sent is 7.5 mS / 708 uS = 10 packets.
Actually 708 uS * 10 = 7080 uS = 7.08 mS. So remaining 0.42 mS is idle (wasted)
2) Assume that connection interval is 8.75 mS.
Number of packets sent is 7.5 mS / 708 uS = 12 packets.
Actually 708 uS * 10 = 7080 uS = 8.496 mS. So remaining is only 0.254 mS is idle (wasted) (8.75 - 8.496 = 0.254 mS)
3) Assume that connection interval is 11.25 mS.
Number of packets sent is 11.25 mS / 708 uS = 15 packets
Actually 708 uS * 15 = 7080 uS = 10.620 mS. So remaining is 0.63mS is idle (wasted).
If you compare 1 and 2, increase in connection interval will result in less idle time. So increased throughput.
If you compare 2 and 3, increase in connection interval will result in more idle time. So less throughput.
So throughput and connection interval will not have a linear relation. However, if you increase the connection interval, power consumption will decrease. And vice versa. Because, less the connection interval, more often it has to be switched from sleep to awake and vice versa.
Show LessThe iOS application is written to scan for WICED Sense Kit around your iOS device , connect to it and start publishing the sensor data to quickstart.()IBM Internet of Things Foundation
You can refer to the iOS attached applicaiton, this iOS application generated a random cliend ID which can be fed in quickstart page to see the data.
External packages used : BLE library for iOS, Moscapsule for MQTT library
Note : size classes are not used, resolution for different iOS devices might not be scaled
1. You can use the WICED Sense SDK as is or you can program the WICED Sense using the WICED Smart SDK, you can download the WICED Smart SDK from https://community.broadcom.com/community/wiced-smart
2. The WICED sense comes with default firmware loaded to keep advertising the five sensor data ( Gyro, Accelerometer, e-compass,temperature and humidity
3.With in the SDK there is a sample application called wiced-sense , the default applicaiton loaded on all sense tags. You can modify based on your needs and download the application to your hardware using the below make target
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:
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 BCM20737 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:
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):
For unused dual bonded pins, the unused GPIO should be input/output disabled (especially when it is an input).
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.
Show LessHello. Here is an example app that is capable of swapping between advertising and scanning.
BLE advertisement packets consists of 31 bytes. Each field (i.e. appearance, name, service UUID or similar) has a header of 2 bytes (length and type), meaning that the maximum user payload is 29 bytes. That means the more fields that are packed into one advertisement packet, there are less bytes freed for user payload.
Here's an example of advertisement data(AD) from Bluetooth SIG documentation. (pdf attached)
You can view all the different data types and formats in the documentation attached.
In our SDK, each field is represented by BLE_ADV_FIELD data structure. Here's the definition:
typedef PACKED struct
{
UINT8 len; //length of field
UINT8 val; //value of field
UINT8 data[ADV_LEN_MAX-2]; // This is the data and the biggest one is 31-2 = 29
} BLE_ADV_FIELD;
Notice the length, value, and the actual data in the struct corresponds to how AD is formatted in the example above.
You can change the advertisement packet by defining the fields in an array and initializing them.
BLE_ADV_FIELD adv[2];
// Format advertisement data. Data consists of 2 fields. Standard Advertisement flags
// and Broadcom Vendor specific data. The vendor specific data consists of
// 16 byte UUID and a message "Hello"
// flags
adv[0].len = 1 + 1; // 1 (data length) + 1 (value)
adv[0].val = ADV_FLAGS;
adv[0].data[0] = LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED;
adv[1].len = 23 + 1; // 23 (data length) + (value)
adv[1].val = ADV_MANUFACTURER_DATA; // (AD_TYPE == 0xff)
adv[1].data[0] = 0x0f; // Broadcom (Company Identifier 2 bytes)
adv[1].data[1] = 0x00;
// Set UUID
BT_MEMCPY(&adv[1].data[2], mybeacon_uuid, 16);
// Set "Hello" message
BT_MEMCPY(&adv[1].data[18], msg, 5);
Here are the field values:
// ADV flag values enum ble_adv_flag_value { ADV_FLAGS = 0x01, ADV_SERVICE_UUID16_MORE = 0x02, ADV_SERVICE_UUID16_COMP = 0x03, ADV_SERVICE_UUID32_MORE = 0x04, ADV_SERVICE_UUID32_COMP = 0x05, ADV_SERVICE_UUID128_MORE = 0x06, ADV_SERVICE_UUID128_COMP = 0x07, ADV_LOCAL_NAME_SHORT = 0x08, ADV_LOCAL_NAME_COMP = 0x09, ADV_TX_POWER_LEVEL = 0x0A, ADV_CLASS_OF_DEVICE = 0x0D, ADV_SIMPLE_PAIRING_HASH_C = 0x0E, ADV_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F, ADV_TK_VALUE = 0x10, ADV_OOB_FLAGS = 0x11, ADV_SLAVE_CONNECTION_INTERVAL_RANGE = 0x12, ADV_SERVICE_SOLICITATION_UUID16 = 0x14, ADV_SERVICE_SOLICITATION_UUID128 = 0x15, ADV_SERVICE_DATA = 0x16, ADV_TARGET_PUBLIC_ADR = 0x17, ADV_TARGET_RANDOM_ADR = 0x18, ADV_APPEARANCE = 0x19, ADV_ADVERTISING_INTERVAL = 0x1A, ADV_SERVICE_SOLICITATION_UUID32 = 0x1F, ADV_SERVICE_DATA_UUID32 = 0x20, ADV_SERVICE_DATA_UUID128 = 0x21, ADV_SECURE_CONNECTION_CONF_VALUE = 0x22, ADV_SECURE_CONNECTION_RANDOM_VALUE = 0x23, ADV_INDOOR_POSITION = 0x24, ADV_3D_INFORMATION_DATA = 0x3D, ADV_MANUFACTURER_DATA = 0xFF, };
Then, you'll have to call bleprofile_GenerateADVData function to actually generate the AD.
bleprofile_GenerateADVData(adv, 2);
where the first parameter is the array to BLE_ADV_FIELD and the second is the number of fields.
You can start advertising in few different ways.
If you have the BLE_PROFILE_CFG defined for the app, then you can simply start by calling:
bleprofile_Discoverable(HIGH_UNDIRECTED_DISCOVERABLE, NULL);
Or you can start advertising by setting up the advertisement parameters yourself.
blecm_startAdv(
HCIULP_ADV_NONCONNECTABLE_EVENT, // non-connectable undirected advertisement
160, // adv interval 100 msec
HCIULP_ADV_CHANNEL_MAP_MASK, // all channels
HCIULP_PUBLIC_ADDRESS, // int advAdrType,
HCIULP_ADV_FILTER_POLICY_WHITE_LIST_NOT_USED, // int advFilterPolicy,
HCIULP_PUBLIC_ADDRESS, // int initiatorAdrType,
NULL);
Advertisement packets have different types.
The first argument to this function, blecm_startAdv defines the type of the advertisement.
Value Passed | Advertisement Type |
---|---|
0x00 | ADV_IND |
0x02 | ADV_DISCOVER_IND |
0x03 | ADV_NONCONN_IND |
You can refer to the "auto-generated API" for more details on this function.
In order to start scanning, you simply need to call blecen_Scan function.
blecen_Scan(HIGH_SCAN);
Or to turn it off:
blecen_Scan(NO_SCAN);
You need to register a handler if you want to do anything with the advertisement packet in the app create function.
void advertisement_handler(HCIULP_ADV_PACKET_REPORT_WDATA *evt);
...
void basic_create(void)
{
...
// register to process peripheral advertisements
blecm_RegleAdvReportCb((BLECM_FUNC_WITH_PARAM) advertisement_handler);
...
}
I have made an example app that swaps its role between advertising and scanning. The files are attached as adv.h and adv.c
The app first starts scanning, but you can change its role by pushing the button on the board. It has a minimum RSSI value, so you'll need to have advertising device close to the scanner in order for the scanner to pick up the advertisement.
I was able to put the code into two Tag 3 boards and test their functions.
Here's the app in action.
Notice how the advertisement data corresponds to how we set the BLE_ADV_FIELD array above.
James
Show LessRevision | Description | Date |
---|---|---|
1.0 | I2C Description | 10/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:
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:
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 >> 😎 & 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), ®ister_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;
}
Show Less
The attached app shows sample usage of the ADC hardware built into the 36/37/s chips.
To use the app, load it onto a Tag board that has a push button on P0. Run traces on the board. You'll initially see ~0V, and when you press the button you'll see the applied voltage on the voltage rail (~3300mV).
There are three necessary steps to get the ADC running, as seen in the app:
Import:
#include "adc.h"
Instantiate in create function:
adc_config();
And poll the ADC using the function:
adc_readVoltage(adc_convertGPIOtoADCInput(gpio_number));
*Calibration occurs within the initialization function. However, it may be useful to your application to calibrate the ADC to an external voltage for added assurance, or to do so periodically throughout the run-time of your application. To do so, call the function below: parameter one is the known voltage of the reference source in mV, and parameter two is the location of the reference voltage. The location can be configured to many different buses and all GPIOs (for external sources). Control click the second parameter within the source code to see a complete list of the locations that can be utilized as a reference voltage.
adc_adcCalibrate(2000, ADC_INPUT_VDDIO);
The output of the polling function is in mV.
More info on the ADC:
BCM20737S - ADC Noise-free resolution
Questions related to the ADC implementation on the BCM2073XS...
BCM20737 ADC DMA or Interrupt Service Routine
Show LessHello Everyone,
See the attached file for an example of use of the PUART.
To use the sample code, load it onto two Tag boards, connect the boards via PUART, rx-to-tx, with a common ground (currently setup for P32, P33). Run HCI traces (default) on one board and click the button (P0) on the other board. An incrementing value, starting at 0, will be displayed on your terminal with every click of the button. This value was sent via PUART from the peripheral board (the value will increment twice on every click because the button registers an interrupt on each rising and falling edge).
Jacob
Show LessProduct Selection | Product Evaluation | WICED Sense | Product Development | Manufacturing / Production |
Revision | Change Decription | Date |
---|---|---|
1.0 | Initial Video - No Audio - 6 minutes | 06/23/14 |
1.1 | Added Audio | 06/24/14 |
1.2 | Added detailed Smart Designer video - Uses Microbrewery and Beer Drone as Services and Characteristics explanation | 09/22/14 |
Hello Community Members,
Welcome to the WICED Smart Video BLOG Series
This Video BLOG should be used as a "guide" for walking through the Smart Designer Tool in SDK 2.1.
This video will illustrate a great feature to use for configuring the GATT for Bluetooth SIG approved profiles + Vendor Specific Profiles.
This Smart Designer Walk-Thru uses a Sensor Device with the following sensors needed to be configured with Vendor Specific Characteristics:
We have made it fun by showing a Microbrewery Sensor Configuration and a Beer Drone example - Hope you enjoy it!
It is a big file and 30 minutes, so view it when you have some time.
New Video starts here:
Thanks
JT
Show LessRevision | Change Decription | Date |
---|---|---|
1.0 | Initial Video - No Audio - 10 Minutes | 06/24/14 |
1.1 | Added/Edited Audio and Video | 06/25/14 |
1.2 | Added Text Annotations | 07/01/14 |
1.3 | Added Part 2, 3, 4, 5 and 6 without Annotations | 10/08/14 |
Hello Community Members,
Welcome to the WICED Smart Video BLOG Series: Interviews with the Experts.
Experts Interview - Sleep Deep_Sleep and Advertising
This Video BLOG should be used as a "guide" for walking through the Sleep and Deep_Sleep functionality with respect to the hello_sensor app in the SDK 2.0.1.
We will interview with Sleep Deep_Sleep expert A.S. and hear his explanation of the Sleep and Deep_Sleep control that the SDK 2.0.1 firmware uses for the hello_sensor example app in the SDK 2.0.1
We also discuss:
Thank you A.S. for your help in this explanation:
Part 1:
Part 2:
Part 3:
Part 4:
Part 5:
Part 6:
JT
Show Less