In my last post, we saw how flexible and powerful the Cubieboard can be, with the correct knowledge of the pin multiplexing and choosing the pin functionality for your application. Given that you have 7 UART ports, and around 3 SPI ports at your disposal, you can only imagine the power that this gives you.
The company that produces the SoC on which the Cubieboard is based on, AllWinner, primarily wanted to develop this chip as a cheap alternative to Android enabled device manufacturers, such as phones, tablets and what not! And hence, the chipset and subsequently the development boards, are powerful, flexible and have ports designed for external device interfacing, including 2 camera interfaces. (However, only one can be active at one time, like front cam and back cam) But, what it makes for in these interfaces, it lacks in the number of ADC’s (Only one, for accelerometer. People argue that it has the ADC’s for the LCD screen, but involves hacking the driver files, interesting project if someone is willing me to pay for it) and PWM channels. Basically, you cannot collect data or move motors by just using the Cubieboard.
So, if you are planning to use the Cubieboard in your Embedded Design Project, you will sooner or later have the need to communicate with a daughter board, either for getting a bunch of sensor data, or performing some actuation. This post comes as a result of a similar need I had, where I had to trigger a bunch of OpenCV codes which depended on certain sensor values.
Since I could not interface my sensors on the Cubieboard, I decided to use an Arduino for measuring the sensor data and communicate the processed values to the Cubieboard via UART.
The Cubieboard has 8 UART ports in all, including the 4-pin TTL port. However, this 4 pin TTL by default is used in the following ways:
- Console Messages (including bootup messages)
- A getty so you can login via serial
So, I would suggest that you avoid using the TTL pins, since you would need to edit the boot and initab files in order to use them. Plus, this port comes in very handy for debugging purposes. So instead, we will configure the other GPIO pins for UART.
On the Arduino side, instead of connected pins 0 and 1 (The default UART pins) , I decided to use the SoftSerial library instead. Why? Because I wanted to hook up my Arduino to my PC via USB, whilst it communicates with the Cubieboard, for debugging purposes.
Now I will show the codes on the Arduino and the Cubieboard side respectively, after which you can safely wire up the proper pins on both sides and communicate seamlessly.
Arduino side:
As mentioned before, I won’t be using the default serial pins for interfacing and instead use the SoftSerial library to configure pins 2 and 3 instead. However, the SoftSerial library does not support baudrates above 9600. We will see how that is actually a good thing for us later. Following code snippet sends a character to both serial ports if the ADC value is above a threshold, and prints whatever value it gets from CubieBoard to the PC:
/* Connects Arduino to Cubieboard Arduino: SoftSerial Raspberry Pi: GPIO UART Based on Arduino SoftSerial example */ #include SoftwareSerial mySerial(2, 3); // RX, TX int pressure; int THRESHOLD = 500; void setup() { // Open serial communications to PC and wait for port to open: Serial.begin(57600); // set the data rate for the SoftwareSerial port to Cubieboard mySerial.begin(9600); // Set A1 as input sensor pinMode(A1,INPUT); } void loop() // run over and over { // Measure the sensor value pressure = analogRead(A1); // If pressure crosses the threshold, send character to both ports if(pressure>THRESHOLD) { Serial.write("Y"); mySerial.write("Y"); } // If data is available on Cubieboard, print it to PC if (mySerial.available()) Serial.write(mySerial.read()); }
Cubieboard side:
First order of business would be to configure a UART port of our choice on the Cubieboard. For this case, UART5 is an optimal choice, it has only the Rx and Tx ports, just like the Arduino side, thus not wasting any GPIOs unnecessarily.
Now we make changes in the fex file like mentioned in my previous post and note down the pins:
[uart_para5] uart_used = 1 uart_port = 5 uart_type = 2 uart_tx = port:PH06 uart_rx = port:PH07
The pins are : Tx (Port H, pin 6) and Rx (Porn H, pin 7)
Make sure to compile the fex file to an appropriate bin file, otherwise the changes will not be seen.
Just to check all the UART ports that you have, you can just list by the following command:
ls /dev/tty*
OR
dmesg|grep tty
Now for the communication part, hackers tend to use Python due to the ease with which you can perform serial communication, thanks to the PySerial library. But in my case, since I had to trigger some OpenCV based codes, I decided to go the C++ way, since I could just include a header file in the main file and save a lot of unwanted mess.
Serial Initialization function
Although you can just open the Serial Port on any linux box as a file, you need to define some flow control and flag options for the desired communication terminal since this is an asynchronous communication and follows a proper handshaking protocol(If you need more clarification on this, please mention on the comments). So we will need some standard libraries for this purpose, you can add them like this:
#include #include <sys/ioctl.h>
Now we initialize the serial port terminal options :
/*Init function, takes serialport address and baudrate as input */ int serialport_init(const char* serialport, int baud) { struct termios toptions; //from the termios lib int fd; //file descriptor
Next step would be to open the port with the proper flags and initialize the input and output data speed equal to the input baudrate:
//Open the port as a file //O_RDWR = Open as read and write //O_NOCTTY = TTY file not to be used for control purposes fd = open(serialport, O_RDWR | O_NOCTTY) //set the baudrate speed_t brate = baud //setting the input and output speed cfsetispeed(&toptions, brate); cfsetospeed(&toptions, brate);
Now that the serial port has been initialized with the correct options, you can just read it as a file and accordingly write the functions for them. For the complete code with the read and write functions, please refer to this link.
Now you can include this library in your main file and initialize the port like this:
serialport_init("/dev/ttyS5", 9600);
Final Connections:
Now that we have configured the UART pins and written the appropriate code on both ends, time to hook them up. Following are the pin outs:
Cubieboard | Arduino |
Rx – Port H, pin 7 | Rx – pin 2 |
Tx – Port H, pin 6 | Tx – Pin 3 |
The possibilities from here are endless, you can send commands from the Board to the Arduino and use them to control motors or actuators. In case you need further clarifications on any of these, feel free to drop a comment here!
NOTE: I mentioned before that the 9600 baudrate on the Arduino is actually a blessing in disguise for us, that is because Arduino supports only 2 pin UART, which is actually not at all ideal for a full duplex communication. Imagine this scenario, the Arduino sends some data and triggers a code on the Cubieboard, now any data that the Arduino sends while the Cubieboard is still executing the code will be lost because of the lack of proper data control pins. A quick fix around this would be to run a thread which accumulates the sensor data in a buffer on the board, or to time your code properly so that it finishes executing before the next data comes in
Happy Tinkering!