This section of the report covers my contributions towards the development of the motion control interface.
My task for the system was to implement and program all the hardware devices and make data available to the receiver program running on the PC. This includes the configuration of all Prospeckz devices and implementing protocols for radio transmissions communication back to PC. I was also tasked with setting up the accelerometer chip(s) for data gathering. To do this, I split the problem into several requirements:
The Prospeckz devices:
- The implementation of reliable radio communication between transmitters and receiver
- Development of a communication protocol between accelerometer and transmitter
- Wired transfer of data from receiver (base station) to PC
The wireless communications between hardware devices were initially required to support a single transmitter, however this requirement was amended in later stages of system development to support receiving data from multiple transmitters with minimal losses.
To define the format of data transferred from receiver to PC, I worked closely with Li to create a compact and efficient format that conforms to the standards of my implementation and the PC processor that he worked on.
- Design the circuit peripherals around the chips and mount them on protoboards for testing, later switching to small PCBs to integrate with transmitters compactly
- Set up the accelerometer's initialization and data retrieval
Initially the group had an idea to also incorporate a gyroscope into the hardware implementation to increase the system's capabilities, however no devices were available and in the end only an accelerometer proved to be sufficient.
In response to the requirements above, I tackled each task individually, making sure the implementation is robust before moving on to the next stage. I first implemented the radio communications between transmitter and receiver, using test programs on the Prospeckz such as the Cycling Led example in the Prospeckz Guide to verify by design.
I then worked on creating a relay system that would transfer data received by the base station to a PC through a USB (TTL) cable.
Finally, I worked on configuring the accelerometer and setting up the protocol by which to extract raw data and send wirelessly by the transmitter.
The ProSpeckz IIK (Programmable Speck using Zigbee Radio) was used extensively in this project, as it acted as the main microcontroller for all hardware behavior. Some of its notable peripherals include an RGB LED, A Zigbee Radio Chip with 2.4GHz antenna, one reset switch and one programmable switch, and two 8-bit ports for interfacing with other components. The PSoC CY8C29666-24LFXI is housed within the ProSpeckz as the main programmable component and microcontroller.
A picture of the ProSpeckz IIk from the the ProSpeckz Guide
LIS 33 breakout board
Freescale MMA8451Q breakout board
Sparkfun ADXL345 eval board
All these models incorporate the same basic features: 3-axis measurements, support for I2C master-slave communication, good resolution range and low-power operation. It was a draw as to which device to choose, so I ultimately settled for the MMA8451Q accelerometer due to higher availability in the university and because it was easier to integrate with the rest of the system as a breakout board.
The ProSpeckz was programmed using PSoC Designer 5.1.
The Radio (Prospeckz)
After consulting the accelerometer datasheet and discussing with the group, it was decided that for the wireless communication, a packet size of 8 bytes is compact enough while being sufficient. This is due to the fact that the accelerometer provides data with 14 bit resolution, meaning it needs 2 bytes to store the acceleration measurement from each axis; these 2 bytes are denoted as MSB (most significant bits) and LSB (least significant bits). A total of 3 axes amount to 6 bytes of raw data, to be added together in the packet along with the device's ID (for multi-device support). The packet format is shown below, with each colored box denoting 1 byte (8 bits):
Note that the low-level code controlling the radio appends an additional byte at the end of each packet which contains the packet's length; this is not shown in the diagram above. We left the 8th byte empty in case it was ever needed for additional transfers; Once the group was certain the data transferred is sufficient, the realistic payload of the radio communication was 7 bytes per packet (without overhead bytes).
Additionally, some error-checking had to be performed on the radio communication in order to determine corrupted/incomplete/invalid packets. Deciding that the microcontroller is better suited dedicating itself to the control aspects of the hardware, we build the error-checking into the backend processor executing on the PC. Once packets are received there, each byte is checked against a set of allowed values and is discarded if the system detects it is invalid.
To implement the radio trasmission on the ProSpeckz, the SPI protocol was used through PSoC's SPIM radio module provided with the ProSpeckz template code.
Parameters of the SPIM module.
To test the radio, I used the simple Cycling Led example shown in the ProSpeckz guide to engage two devices in communication, having one device follow the changing LED color of the other.
Base Station USB Transfers
To accomplish data transfer between the receiver (base station) ProSpeckz and the PC, I used PSoC's UART (Universal Asynchronous Receiver/Transmitter) module to configure a pin on one of the device's ports to act as output. I configured the UART module according to the following parameters.
Parameters of the UART module.
The UART protocol is initialized simply by calling the PSoC module function UART_Start(UART_PARITY_NONE). This initiates communication with no parity (an error-checking method). Since the system already has stringent checks for data validity based in the processor, a no-parity link is deemed sufficient to fulfil the system's requirements.
Once the UART has been initialized, the data transfer was accomplished through the following two functions provided by PSoC:
UART_PutSHexByte( byte b ) - This function puts byte b on the UART bus in hexadecimal format.
UART_CPutString( string s ) - This function puts string s on the UART bus in human-readable form.
The distinction between the two is very important as encoding and data representation is an issue. In my code, I generally used UART_CPutString() to insert characters/line-breaks between bytes or sets of data for easy retrieval later; I also used string communications for debugging/showing errors in the console. PutSHexByte() was exclusively used to relay raw data from the accelerometer to the UART bus.
Setting up and configuring the MMA8451Q accelerometer by far proved to be the most time-consuming and challenging task for me, for a few reasons.
Firstly, the breakout board required separate external decoupling capacitors to stabilise the power supply to the device and prevent voltage spikes. Pull-up resistors were also required on the output pins in order to properly communicate with the controller (the ProSpeckz). After examining the device's datasheet to find the accelerometer's Pinout information (Page 5, MMA8451Q-datasheet), I was still unsure how exactly to wire the external components to the device. Exploring further, I found the Application note AN4077 which describes the basic board mounting guidelines for the device. Following the pinout information and Figure.2 of AN4077 (shown below), I was able to mount the accelerometer on a protoboard with all external components.
Circuit schematic for the MMA8451Q.
Lastly, I implemented the communication protocol that accomplishes the retrieval of data from the slave device (accelerometer) by the master (the ProSpeckz). The MMA8451Q supports I2C communication, a standard protocol invented by Philips to attach low-speed peripherals to motherboards or microcontrollers.I implemented the I2Cm module within PSoC Designer, the parameters of which are shown below.
Parameters of I2Cm module
From the I2Cm datasheet, I was able to use the example C code to perform reads and writes to the accelerometer with a single-master single-slave configuration. Firstly, upon startup, the accelerometer is initialized from Standby Mode by writing 0x01 to the accelerometer's control register (address 0x2A); This puts the device into Active mode, where data measurements are being taken continuously.
To read and write data from master to slave through the I2C protocol, I observed the following steps:
To write to the device (such as modifying control registers), use the function
I2Cm_bWriteBytes(slave_addr, data, length, I2Cm_CompleteXfer)
making sure that the parameter I2Cm_CompleteXfer is used, and that the first element in the data is the register address to write to, with the second element being the data to be written. For example, to set the device from Standby to Active mode, I ran the following code:
I2Cm_bWriteBytes(1C, buffer, 2, I2Cm_CompleteXfer)
where buffer is simply an array with the elements [0x2A (register address), 0x01 (the data to write to that address).
Reading from the slave is a bit different. What must be done is, first write to the device the register address you want to read from, and then read from the device and store the result in a buffer. The write function here basically just specifies a register address, and the accelerometer uses that address when executing the next read operation.
I2Cm_bWriteBytes(1C, buffer, 1, I2Cm_NoStop)
I2Cm_fReadBytes(1C, data, 1, I2Cm_RepStart)
where buffer is a 1-element byte array with the register address. the I2Cm_NoStop and I2Cm_RepStart parameters simply allow for batch transfers of this kind to take place within one I2C transfer cycle, improving speed and performance.
By using these functions, I was able to program the master to initialize the accelerometer upon startup, and begin to continuously read data from the X,Y and Z register (0x01 - 0x06). These 6 bytes of data are then added to a packet along with the device's ID and sent across the radio to the receiver ProSpeckz, which then relays that packet through UART to the processor system (developed by Li with some help from me to ensure format consistency), which translates and formats the raw bytes into readable and usable information.
Following the implementation stages outlined above, I managed to design a robust hardware system as the backbone of our intended goal: to transfer acceleration data from a hand-held (wireless) device to a computer, where it is processed and formatted to control an array of different applications. In this section I will describe some of the technical details for each of my implementations, as well as how they perform.
For receiving, the device loops checking the FIFOP_Data_ADDR & FIFOP_MASK; If true, it receives the packet and waits for success, or prints an appropriate error message if failure.
For transmitting, there is a delay between every 2 packets sent. The delay is implemented by a simple nested loop which holds up the processor while executing. I used Radio_delay(121), so:
121 (first loop) * 256 (second loop) = 30976 cycles delay
From the ProSpeckz datasheet, the System Clock runs on 24MHz, but the radio operates on half that frequency, ie 12MHz. From this we deduce that the approx. number of packets sent per second is:
12 MHz / 30976 = 387 Hz (packets per second per transmitter)
This transmission rate was adequate for the display to fluidly react to acceleration changes. Furthermore, it allows the use of multiple transmitters (at 387Hz each) since the receiver does not implement any delay and is therefore capable of receiving at a much higher frequency.
The contents of each packet are in hexadecimal encoding (signed 2's complement notation) and are transmitted in that form.
The UART communication uses a TTL-to-USB cable which required a driver installation when running the program in windows. Only the UART-receive wire on the cable was used, as I decided there is no need for the computer to be sending commands to the ProSpeckz.
Data is sent to the PC in a format similar to that of the packets received, instead this time I needed to put break characters between each byte to make them extractable by regular expression and splitting in later stages. I used the "," character between bytes and a line break ("/r/n") between packets.
I did not implement any specific modes and configuration for the accelerometer due to time constraints; instead I settled with continuously reading data. The ProSpeckz will read data from the accelerometer regardless of whether readings have changed (as a group we applied this in the processor system). The main results for this section are the circuit board.
Completed accelerometer circuit together with ProSpeckz and all other components.
The wireless sensor in a box.
The second device (without box here)
On power consumption, this was measured using the bench-top power supply while the wireless device was operational. By monitoring the voltage and current consumption, I was able to to calculate the average power consumption during Active mode to be approx.
3.3V (avg) * 0.1A (avg) = 0.33W = 330mW
Thus, the devices lived up to their low-power promise. Given the above result, an array of 1800mWh batteries can power a single device for ~5.5 hours before getting depleted.
Overall, I think I did a good job with the basic implementation and testing of the hardware. All the requirements were met, providing a robust and efficient hardware system for the wireless and wired transfer of data across devices and with many different protocols.During the time of the project, I spent much time working alongside Li to ensure work on the processor was consistent with the data my hardware system would transmit. I would also like to thank Guy Taylor (from Group B) for offering help in figuring out some C code and general debugging of aspects of the ProSpeckz that were beyond my programming knowledge.
Taking part in this system level integration has given me new appreciation of the effort that must be put into designing a robust, multi-faceted system from scratch. Team work and communication were of utmost importance, and I think me and my group managed to be on the level and ultimately design a working and flexible solution for applications seeking to use motion control for their purposes.
Further work and Improvements
My implementation utilizes only one source code file (main.c) which was based on the ProSpeckz Template offered on the SLIP course website. The way in which receiver and transmitter devices are separated is by a boolean variable (isSender), which I changed the value of based on which device I was programming at the time. I used the same method to give the two transmitters a different deviceID before programming. This was enough for the code to work, however more could have been done in writing cleaner, and possibly more efficient code.
There are some hardware issues that have still not been addressed. When both devices are transmitting, the device that was turned on last has a slight latency, due to its packets arriving after the first's, in an alternating fashion. This was visible in the demonstration with the drawing pad application, where the 2nd line would draw slightly slower. A better algorithm for supporting multiple devices would have to be developed in order to give devices equal priority.
Furthermore, while i succeeded in soldering circuits that worked, a lot could have been done with making the wiring and the whole device more compact. Due to time constraints I was unable to design a very good circuit board.
AN4077: MMA845xQ Design Checklist and Board Mounting Guidelines
PSoC functional blocks (all, screenshot)
Source code: main.c
This code is a modified version of the template written by James Mathews, who in turn based it on work by Steven Wong and Matthew Barnes.