The example project files in the zip attached to this knowledge-base article are meant to create a customized firmware for the BT121 that demonstrates the simultaneous SPI communication between the BT121 and the display + accelerometer that are found in the main board of the DKBT development kit.
The main functionality provided by the application embedded in this firmware is to let the module autonomously read the x-axis and y-axis g data from the accelerometer at the desired interval, and then present such data to the user via the display. Additionally, the application is designed to control the main board’s LEDs so that they turn on and off depending on the orientation of the board, while at the same time the same data presented at the display is also sent out of the module’s UART interface, with the added z-axis measurement.
The main parts of the two key project files (the hardware.xml and the acc_demo.bgs) are discussed below. However, in order to better understand the whole example, please refer to the documentation of the accelerometer (ADXL350 from Analog Devices) and of the display (NHD-C0216CZ-NSW-BBW-3V3 from Newhaven Display International) in addition to all the documentation of the BT121.
Let’s see at first the hardware configuration file. This is called hardware.xml and it contains the following entries which are relevant in this project:
<uart baud="115200" flowcontrol="true" bgapi="false" /> <spi channel="1" alternate="2" clock_idle_polarity="high" clock_edge="1" endianness="msb" divisor="256" /> <port index="0" output="0x6000"/> <port index="1" output="0x7600"/>
The first entry enables the UART interface to operate at a baudrate of 115200 with RTS/CTS flow control, and disables the BGAPI protocol over it, since this interface is only used for debugging purposes while the module is supposed to operate in standalone mode and not in Network Co-Processor (NCP) mode. The second entry enables and configures the SPI interface of the module over which the communication with the accelerometer and the display is being carried. With the last two entries the exact GPIOs to be taken in use as outputs are defined.
The most important project file is the BGScript by which we are designing the actual built-in functionality. This is the acc_demo.bgs and its basic-like event-driven code comes with comments that should help in clarifying the commands/events and also the flow of the application.
At boot the script initializes the GPIOs in use and set them all high, then immediately proceeds with the initialization of the display. The second event always generated by the system is the system_initialized event: this comes when the radio chipset has become ready and carries the MAC address of the module, so the script has some code under this event to capture the address data and process it so to present it in human readable format in the first row of the display. Back to the display initialization, below you can see how this is done:
call hardware_write_gpio(1,$4000,$0) call hardware_write_gpio(0,$6000,$2000) call endpoint_send(spi_endpoint,11,"\x30\x30\x30\x39\x14\x56\x6d\x70\x0c\x06\x01")
With the first line we are setting low the pin 14 of port B (PB14) which is connected to the LCD’s Register Select input (where 0=Instruction and 1=Data). With the second line we are setting low the pin 14 of port A (PA14) which is connected to the LCD’s active-low Chip Select (CS) input, while maintaining the pin 13 of port A (PA13) high as this carries the corresponding CS signal for the accelerometer which is not yet supposed to listen to data from the module. When the calls in the first two lines are executed the script will launch the next call to send the 11-bytes initialization string over the SPI interface to the LCD.
As can be noticed above, the last call is not followed by an instruction to return the CS line to the high state: in fact it is important to highlight here that there has to be always a certain delay after the last byte is sent to a peripheral before the corresponding CS line is set back high. This delay is taken care by arranging for the CS status change to happen always after the script has processed the data coming from the peripheral (or after a timer). This is seen for example in the code below which exists for the subsequent initialization of the accelerometer:
event endpoint_data(endpoint, data_len, data_data) […] if endpoint = spi_endpoint && data_len = 11 then call hardware_write_gpio(1,$4000,$4000) call hardware_write_gpio(0,$6000,$4000) call endpoint_send(spi_endpoint,2,"\x2d\x08") return end if […] end
As can be noticed above, only after the script has received the 11 bytes from the LCD the instruction to raise the PB14 is given, so to turn the LCD into data mode (since from now on only characters to show will be sent to the LCD), and then PA14 is turned high while at the same time the PA13 is turned low to make sure that the next 2-bytes initialization string sent out of the module will reach the accelerometer.
The same endpoint_data event is then processing similarly the 2-bytes data coming from the accelerometer, in which case both CS signals are returned to the high state and a one-shot timer is started.
When this particular timer has expired the LCD is ready to receive the characters to display (given that the Register Select line is already high) so within the event hardware_soft_timer, and under the handle of 0 that was used when the one-shot timer was started, the LCD’s CS line is set low and display data is sent to LCD (including at this time only the MAC address.) After the data is sent to the display, the CS line is not set to high as discussed above, but a new timer, repeating at the desired interval, is started with handle of 1.
From this moment the application enters in a loop triggered by the repeating timer: at every timeout the accelerometer data will be read then the data will be presented at the display and out of the UART and will also be used to decide under which circumstances one of the evaluation board’s LEDs will be turned on. All of this is implemented in the following way according to the script:
event hardware_soft_timer(handle) if handle = 1 then call hardware_write_gpio(0,$6000,$4000) call endpoint_send(spi_endpoint,7,"\xf2\x00\x00\x00\x00\x00\x00") return end if […] end
Above, when repeating timer has expired, simply the appropriate 7-bytes string is sent to accelerometer after switching the PA13 low and the PA14 high. A comment in the BGScript briefly describes the syntax of that strings, which in practice commands the accelerometer to return the current g values of the 3 axis.
And then we have the following code (simplified so that only the code related to the x-axis is shown):
event endpoint_data(endpoint, data_len, data_data) if endpoint = spi_endpoint && data_len = 7 then display_data(40:2)= "X=" display_data(42:1)=HEX(((data_data(2:1)/16)&15):1) display_data(43:1)=HEX((data_data(2:1)&15):1) display_data(44:1)=HEX(((data_data(1:1)/16)&15):1) display_data(45:1)=HEX((data_data(1:1)&15):1) [...] call hardware_write_gpio(0,$6000,$2000) call endpoint_send(spi_endpoint,80,display_data(0:80)) call endpoint_send(uart_endpoint,,"\r\nX=") call endpoint_send(uart_endpoint,1,data_data(2:1)) call endpoint_send(uart_endpoint,1,data_data(1:1)) [...] call hardware_write_gpio(1,$3600,$0) if (data_data(2:1) & $3) = $1 then call hardware_write_gpio(1,$3600,$200) return end if [...] return end if [...] end
Above, the event endpoint_data comes again as a consequence of the 7 bytes sent with the instruction under the repeating timer, and when the expected data is captured into the data_data variable the script will in order 1] prepare the hex data into human readable format for the display, 2] switch the PA13 high and the PA14 low (opposite compared to the status changes commanded under the timer), 3] send the display data to LCD over the SPI, 4] send the same data out of the UART, 5] turn all LEDs off just before checking the content of the most significant bits of the x-axis and y-axis readings in order to then switch on the appropriate LEDs depending on the board’s orientation.
As written in some of the comments in the script which are not reported in the code above or in the previous parts, let’s highlight also here that data_data(2:1) holds the most significant byte of the twos complement x-axis measurement while data_data(1:1) the least significant, and let’s remind here as well that readings are 16-bit twos complement but resolution is set to 10bits and that is why the two least significant bits of the most significant byte are checked to define if to turn on a LED or not.
Important notice: the official version 1.1.0 build 154 has a known bug that prevents proper SPI communication (actually module’s incoming data is corrupted), so in order to test this firmware, or if you need a working SPI for your application please consider the newer firmware version 1.1.1 build 168 or newer. In addition, notice that since firmware version 1.1.1 build 168 a new command exists which is fully dedicated the communication over the SPI communication: this is called hardware_read_write_spi and is discussed in the companion article at http://community.silabs.com/t5/Bluetooth-Wi-Fi-Knowledge-Base/BT121-firmware-example-HID-air-mouse-based-on-SPI-communication/ta-p/187248