BT121 firmware example – HID “air” mouse based on SPI communication with DKBT's accelerometer

by <a href=""><font color="#000000"><font size="2">Hero Employee</font></font> </a> enr_tad on ‎01-15-2017 11:30 PM - edited on ‎02-21-2017 10:59 AM by Administrator Nari

In this knowledge-base article we propose to the reader’s attention an example project which is a combination of the customized firmware already presented at and the example under the directory \example\classic_hid_mouse_demo\ of the SDK which is discussed in detail in the application note called “AN1032: HID over Bluetooth BR/EDR” and found at under the “Application Notes” section.


In the previous article we wanted to demonstrate how to enable the SPI communication with the accelerometer and the display which are integrated in the DKBT. The accelerometer in particular was read so to turn on and off the DKBT’s LEDs depending on the orientation of the board among others.

On the other hand, the example in the SDK is meant to demonstrate how the module can be used to enable a simple wireless mouse based on the Bluetooth Classic’s HID profile. With this example, the mouse pointer is remotely moved up and down, left and right, by pressing the DKBT’s buttons.

With the example project files shared here, we want to turn the DKBT into a Bluetooth “air” mouse, allowing the mouse pointer to be remotely moved similarly, but controlled instead by the orientation of the board being revealed by the regular accelerometer’s readings over the SPI interface while the board is being tilted.


Another important reason for sharing this project is to disclose a new command which is dedicated to reading and writing data over the module’s SPI interface: this new command is introduced since version 1.1.1 build 168 of the firmware/SDK and is called cmd_hardware_read_write_spi . This is a very handy command in that it activates at the same time SPI data writing and data reading and Chip Select (CS) signaling, all in all replacing with a single command the sequence of commands and events cmd_hardware_write_gpio + cmd_endpoint_send + evt_endpoint_data + cmd_hardware_write_gpio seen in the previous article for the same functionality, while removing the limitation of having to wait for a short interval before returning the CS line to the un-select state, which was also a point of concern in the previous article.


Also with this example project the most of the discussion goes for the BGScript called here air_mouse.script.bgs .

Among the rest of the project files (most already covered in the application note and in the previous article mentioned above), the hardware configuration file called hardware.xml and the gatt.xml defining the GATT database are worth an annotation: the latter is not so critical, given that in this example the BLE part is not touched, however it has been simplified by removing the Health Thermometer Service (a leftover in the project from the previous article), while the option sdp="false" has been added to the <service … > tags in order to prevent the two mandatory GATT services to be loaded as SDP records in addition to the DID and HID records.

As for the hardware-related file, the configuration of the SPI interface is as demanded by the DKBT, the UART interface is kept enabled, this time not for debugging purposes but to enable the DFU re-programming of the module, while the GPIOs in use are configured, some as output (we are still turning on and off the LEDs here when the mouse pointer is being moved) and one as input (for the mouse left-button press when connected, or for restarting into DFU mode when not connected), as seen below from the xml file:


<!-- Accelerometer CS is PA13 -->
<port index="0" output="0x2000"/>
<!-- GPIOs connected to DKBT's LEDs 2 to 5 as output -->
<!-- GPIO connected to DKBT's button 1 as input-interrupt -->
<port index="1" output="0x3600" input="0x100" interrupts_rising="0x100"/>


Back to the script, let’s see now the (new) parts worth of note (the rest is either commented in the script itself or already discussed in the previous article and in the application note.)

When the module is started the two events system_boot and system_initialized are triggered in a sequence. Within the latter we notice the same calls we are seeing in the other scripts as well, so nothing to add here. Under the system_boot event we are configuring the initial state of the output GPIOs, in particular the one connected to the accelerometer’s CS pin is set to high, while all of those connected to the DKBT’s LEDs are set to high as well, but only after the accelerometer is initialized correctly, things that happen also in the system_boot event using for the first time the new command hardware_read_write_spi . This all is summarized in the code below:


event system_boot(major,minor,patch,build,bootloader,hw)


  # Accelerometer CS line high - It will be toggled low then high by the hardware_read_write_spi which will use active low for the pin polarity
  call hardware_write_gpio(0,$2000,$2000)
  # Here setting the accelerometer into measurement mode - POWER_CTL (register 0x2D) to 0x08 to set the Measure Bit
  call hardware_read_write_spi(spi_channel, acc_cs_port, acc_cs_pin, acc_cs_polarity, 2, 2, "\x2d\x08")(resp_result, resp_data_len, resp_data(0:resp_data_len))
  if resp_result = 0 then
    # With the accelerometer initialized, set a repeating software timer with handle of 1 to timeout every 200ms so to regularly trigger the accelerometer's x-axis and y-axis readings
    call hardware_set_soft_timer(200,1,0)
    # All LEDs turned on after the accelerometer is initialized and until a HID connection is established
    call hardware_write_gpio(1,$3600,$3600)
  end if



With the new command hardware_read_write_spi there is no more need to worry about separate commands to control the CS line or additional events to read the data coming from the sensor: all is taken care by the command itself, and the data from the sensor is carried directly by the response to the command.

Above we are also seeing that a repeating timer is started once the accelerometer is initialized. Every time it times out, the code checks if a HID connection is ongoing, and only in that case the sensor is read, then all LEDs are turned off, and finally the value from the sensor is verified for the mouse to be moved (by sending the appropriate HID report with the call bt_hid_send_input_report) and for the intended LED to be turned on, depending on the board orientation. This is summarized in the simplified code below:


event hardware_soft_timer(handle)

  if hid_connected then # Let's process the calls under the hardware_soft_timer only if a HID connection exists
    # Read values from the accelerometer - Notice that the received data in resp_data(2:1) holds the most significant byte of the twos complement x-axis measurement while resp_data(2:1) the least significant (and the same is valid for the y-axis measurement...)
    call hardware_read_write_spi(spi_channel, acc_cs_port, acc_cs_pin, acc_cs_polarity, 5, 1, "\xf2")(resp_result, resp_data_len, resp_data(0:resp_data_len))
    # Let's turn on and off the LEDs depending on the DKBT orientation and move the mouse pointer accordingly
    call hardware_write_gpio(1,$3600,$0) # All LEDs off except in one of the cases below
    if (resp_data(2:1) & $3) = $1 then # When output data for the x-axis is positive and above 255 (that is, above 0.510g - resolution is 10 bits and range is +-g and scale is 2mg/LSB)
      # Only LED2 (PB9) is turned on
      call hardware_write_gpio(1,$3600,$200)
      # Send a HID report corresponding to moving the mouse pointer 10 pixels down
      call bt_hid_send_input_report(hid_endpoint, 2, 3, $0a0000)
    end if


  end if



In the script, events like endpoint_status and endpoint_closing and bt_hid_state_changed exist to take care of the Bluetooth HID connection and disconnection. They are used for example to set the variable indicating if the connection is ongoing, and in case of disconnection to turn all LEDs on, like at the start.

The last important part of the script is shown below and refers to the handling of the interrupt triggered by the press of the button 1 of the evaluation board. Pressing it while a connection is ongoing translates into the HID report being sent to the HID-Host for the mouse button click. Pressing it at a time when there is no connection triggers a reset of the module into DFU module allowing the re-programming of the module using the BGAPI-based DFU commands.


event hardware_interrupt(interrupt,timestamp)

  # When button 1 (PB8) on the evaluation board is pressed while a HID connection exists
  if interrupt = $100 && hid_connected then
     # Send a HID report corresponding to main (left) mouse button click
    call bt_hid_send_input_report(hid_endpoint, 2, 3, $000001)
    call bt_hid_send_input_report(hid_endpoint, 2, 3, $000000)
  end if

  # When button 1 (PB8) on the evaluation board is pressed while there is no HID connection
  if interrupt = $100 && hid_connected = 0 then
    # Reset to DFU mode to allow reprogramming of the module over the UART interface (needs to be enabled in the hardware.xml)
    call dfu_reset(1)
  end if



Please, find more below an attached zip file containing all the project files ready for building this example firmware with the bgbuild.exe from the SDK.

A video of the firmware in action follows, showing the mouse pointer of a Smartphone being controlled with the DKBT: