I'm new with Android developpemnent but I want to write a SPI driver to connect a SPI IC and then an Android application to send and receive data from and to the IC.
From there, I don't really know where to create the driver (and what it should contain) and how to link an application in top of that. I have a customisable Android kernel (9.0 Pie, APQ8096_LA.UM.7.5.r1-03100-8x96.0_P_v5.0) with all its .dts, .dtsi, .c, and so on. I also got an eval board and the adequate documentation for the mapping.
I googled for a week and didn't found what I was looking for. I learned a bit about the device tree system. Since I have a Snapdragon 820 msm8996, I modified "msm8996-blsp.dtsi" and "msm8996-pinctrl.dtsi".
I had this bit of code:
msm8996-pinctrl.dtsi
&soc {
...
spi_0 {
spi_0_active: spi_0_active {
spi_0 {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
function = "blsp_spi1";
drive-strength = <6>;
bias-disable;
};
};
spi_0_sleep: spi_0_sleep {
spi_0 {
pins = "gpio0", "gpio1", "gpio2", "gpio3";
function = "blsp_spi1";
drive-strength = <6>;
bias-disable;
};
};
};
...
msm8996-blsp.dtsi
&soc {
...
spi_0: spi#7575000 { //QUP Base address for BLSP1_QUP0
compatible = "qcom,spi-qup-v2"; //Manufacturer and Model
#address-cells = <1>;
#size-cells = <0>;
reg-names = "spi_physical", "spi_bam_physical";
reg = <0x07575000 0x600>,
<0x07544000 0x2b000>;
interrupt-names = "spi_irq", "spi_bam_irq";
interrupts = <0 95 0>, <0 238 0>;
spi-max-frequency = <5000000>; //Maximum supported frequency in HZ
qcom,infinite-mode = <0>;
qcom,use-bam; // Enable BAM mode
/* Add BAM pipes */
qcom,bam-consumer-pipe-index = <12>;
qcom,bam-producer-pipe-index = <13>;
qcom,ver-reg-exists;
qcom,master-id = <86>;
qcom,use-pinctrl;
pinctrl-names = "spi_default", "spi_sleep";
pinctrl-0 = <&spi_0_active>;
pinctrl-1 = <&spi_0_sleep>;
clock-names = "iface_clk", "core_clk";
clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
<&clock_gcc clk_gcc_blsp1_qup1_spi_apps_clk>;
status = "enabled";
}
...
I build this kernel with
$ ./build.sh msm8996 -j $(nproc)
I flashed my eval board with fastboot and then I went in adb.
$ adb root
$ adb wait-for-device
$ adb shell
# cd /sys/class/spi_master
# ls
// Nothing here
Considering my spi adress is defined at #7575000, I expected the output to be
# spi_0
Is my code correct to enable it (I'm not good with device tree yet)? If so, why isn't visible with adb and how should I make it visible? What should be the next steps to access this SPI with an Android application?
I searched stackoverflow and so many places, but writing device drivers for Android doesn't seem to be common...
There is no need for you to write a SPI driver for snapdragon it is already in the kernel. Maybe you need to write something to connect it to your device.
The easiest way to expose a spi controller to userspace is by mapping spidev to your device
There must be support for this in your kernel (which is added with the CONFIG_SPI_SPIDEV=y config flag) and in the device tree under the bus
Something like this:
&spi_0 {
spidev#1 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "linux, spidev";
spi-max-frequency = <20000000>;
reg = <1>;
};
};
The device tree is compiled together with the kernel and contains among other things your gpio mappings and DMA configurations so the same kernel can serve multiple boards. Make sure android is using your newly compiled kernel and device tree, sometimes it accidentally builds with one of the prebuilt kernels.
After those steps you should have a /dev/spidev0.0 (or some other number) in /dev
With ioctl complex operations can be used.
To verify if your software have full connection to your SPI bus connect a wire from MOSI to MISO the SPI writeread command will echo the same data it receives - remove the wire and verify there is nothing.
At this point should you start communicate with your sensor, and develop its control software.
In above case I would have started to check the log prints from kernel booting to verify it identifies the hardware correctly and the driver is loaded.
Related
I am trying to obtain a bitmap of the number of cores which are online in an android device. I am trying to create a command line tool in C++ that does some additional functionality based on how many cores are on and in particular which cores are available.
I have tried to use the following to try and get the number of cores on in C++:
cpus = sysconf( _SC_NPROCESSORS_ONLN );
This gives me the number of cores in the system but not which cores are presently ON.
Does anyone know a potential way to do this?
There's no clear cut answer to this problem.
You can use nproc to see how many cores you have available, but this won't tell you how many cores you have online.
You can use top to view the utilization of each core. You can then parse the information from top to infer which cores are presently on.
I was able to get the core online status using this:
int numCPU = 1;
char *status = (char*)calloc(32,sizeof(char));
char *directory = (char*)calloc(1024,sizeof(char));
sprintf(directory, "/sys/devices/system/cpu/cpu%d/online", numCPU);
FILE *online = fopen(directory, "r");
if(online)
{
size = fread(status, sizeof(char), 32, online);
}
printf("Core %d status=%d", numCPU, status);
I'm trying to use adb to find the precise available disk space on an Android device. I'm using this in a powershell command:
$deviceInfo = adb shell df
$storageDriveArray = $deviceInfo -match 'data'
$storageDriveString = $storageDriveArray | out-string
$splitStorageDriveString = $storageDriveString -split "\s+"
$freeSpaceString = $splitStorageDriveString[3]
adb shell df
works, but doesn't give me enough precision (1.7G will be reported). df on Android doesn't seem to take parameters, so I can't use df -k or similar to get a more precise value.
Is there an alternative way to do this?
I'm quite new to powershell so please excuse any hacky stuff!
I currently have a HC-06 Bluetooth device connected to my Arduino Mega 2560 in order to receive strings sent from an Android device. With the HC-06 on Serial 0, I am receiving the data without error with the following code:
String inString = "";
int index = 0;
boolean stringComplete = false;
void setup() {
Serial.begin(9600);
pinMode(pwmPin, OUTPUT);
}
void loop() {
if(stringComplete) {
ParseSerialData(); // Parse the received data
inString = ""; // Reset inString to empty
stringComplete = false; // Reset the system for further input of data
}
}
void serialEvent() {
while(Serial.available() && stringComplete == false) {
char inChar = Serial.read();
inData[index] = inChar; // Store it in char array
index++;
if (inChar == '\n') { // Check for termination character
index = 0; // Reset the index
stringComplete = true; // Set completion of read to true
} else {
inString += inChar; // Also store as string
}
}
}
When I try to replace "Serial" with "Serial1" and "serialEvent()" with "serialEvent1()" and move the Bluetooth device to the TX1 and RX1, this program no longer works.
I have read that some people had similar problems when using AVR-GCC 4.4.x and solved the issue by downgrading to 4.3.x, but I have 4.3.2 (on Windows 8.1, same problem has arisen with Arduino IDE 1.0.3, 1.0.5-r2, and 1.5.6-r2).
I added the following print statements (with Serial 0 to print to the monitor on my PC) to the code with the Bluetooth device still on Serial 1:
String inString = "";
int index = 0;
boolean stringComplete = false;
void setup() {
Serial1.begin(9600);
Serial.begin(9600);
pinMode(pwmPin, OUTPUT);
Serial.println("Setting up...");
}
void loop() {
if(stringComplete) {
ParseSerialData();
inString = "";
stringComplete = false;
}
}
void serialEvent1() {
Serial.println("In serialEvent1...");
while(Serial1.available() && stringComplete == false) {
Serial.println("Char in...");
char inChar = Serial1.read();
Serial.println("WTF");
Serial.println(inChar);
Serial.println("WTF2");
inData[index] = inChar;
index++;
if (inChar == '\n'){
Serial.println("Termination char read...");
index = 0;
stringComplete = true;
}else{
inString += inChar;
}
}
}
Doing this, on the monitor I get:
Setting up...
In serialEvent1...
Char in...
WTF
WTF2
inChar typically prints as nothing, but during one test it was printing as an '#' character. The string sent is "s,1\n" from the Android device.
Based on the print out, the serial event is triggered by availability of serial data, but Serial1.available() remains true for only the first iteration, 's' is not read in (nor any of the other characters that do when Serial is used), and a termination character (newline char) is never read in so that I can begin parsing.
I also tried various baud rates with no difference in behavior. Based on reading Arduino documentation, serial port 1 should work just like serial port 0, and I did not miss substituting Serial for Serial1 in any part of the code.
What could be causing errors in communicating over Serial1 in the same way that has worked flawlessly on Serial0?
I also found a related Stack Overflow question, which was solved with something similar to my code (which works perfectly with Serial0 and is based on the Arduino documentation) using an expected termination character (the difference being that his code implements serial reading in the main loop, whereas mine is in a serialEvent). For some reason, it seems that both of us were having issues with Serial1 data not showing as available at the start of the next iteration. For some reason, serialEvent1 is not being called again for me. And I still don't understand why the first/only character read is not 's.' At first I was thinking that the stream was getting flushed before getting to the serial event again, but that still doesn't account for reading in an incorrect first character.
Also, I added the following Serial1 print statement to run multiple times in the Arduino setup and the Android device receives it each time with no errors, so sending data is working just fine:
Serial1.print("b,1\n");
Or even
Serial1.print("A long test message. A long test message.\n");
I'm fairly close to answering my own question now with further testing/debugging. I actually think the answer may end up being hardware-related rather than software. I wanted to find out if the problem was with the data sent from the HC-06 to port 1, or with the reading function of port 1. I basically had serial port 0 read in data, then send it serially to port 1, which would read that data, and send feedback over Bluetooth to the Android device. Serial port 1 read the data fine coming from port 0, so the issue is reading in data specifically from the HC-06. It may simply be a voltage level issue, so the answer may not belong with Stack Overflow. I will leave the question unanswered though until I definitively have found the root cause (allowing for the possibility that I might need some define statement for the HC-06 or serial port 1 for data to be read correctly, though I'm guessing a voltage level conversion may do the trick. I'm not sure why there would be such a difference between Serial0 and Serial1 though).
I solved the problem enabling the pull-up resistor of the RX1 pin:
Serial1.begin(9600);
pinMode(19, INPUT);
digitalWrite(19, HIGH);
Therefore the 3 V is "overridden" by Arduino's 5 V for logical HIGH and zero is pulled down by Bluetooth's TX for logical LOW.
I did it slightly differently by using the INPUT_PULLUP feature to pull the hardware Serial3 pin HIGH:
Serial3.begin(19200);
pinMode(15, INPUT_PULLUP); // Serial3 receive pin
It works a treat. Previously my serial communications between two Arduino Mega 2560s had been mainly corruption with the occasional correct transmission. Now it is mainly the correct transmission. Previously, the time taken to receive a valid serial value was up to 2.5 seconds (due to having to repeatedly retry to get a valid transmit). Now the time taken to get a valid transmit is 20 ms. (I use a twisted pair of single core wires about 35 cm length.)
After checking the serial data lines on my oscilloscope, I was able to come up with a solution to my issue. With the setup described about the related Stack Overflow question (Bluetooth TX → RX0, TX0 → RX1, TX1 → Bluetooth RX), I checked the signals sent by the Bluetooth device and by the Arduino's serial port 0.
The Bluetooth device's signal was low at 400 mV and high at 3.68 V, while the Arduino's port 0 sent low at 0V and high at 5 V. I knew the Bluetooth device was a 3.3V level device, but the Arduino should read anything above about 3V as high, so this should have not been an issue (and it obviously wasn't on Serial 0).
Anyway, I replaced the HC-06 Bluetooth device with a backup one I had purchased and everything works fine with the code using Serial1 that I posted in my question. This Bluetooth device was transmitting low at about 160 mV and high at 3.3 V.
It seems that my problem was rooted in the hardware (voltage levels) as expected, and that for some reason Serial1 is more sensitive to changes in digital levels than is Serial0.
I'm very new to python and I want to make some application that allows me to use the accelerometer values I get from my phone in windows.
With SL4A (python for android) I created client and server scripts to read the values from the accelerometer and send them to the server (running on pc) through a socket.
This is my server code (windows pc):
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('', 5000))
serversocket.listen(5)
while True:
connection, address = serversocket.accept()
buf = connection.recv(64)
if len(buf) > 0:
print buf
and this my client code (android phone):
import android, socket, time
droid = android.Android()
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect(('192.168.2.6', 5000))
def readAcc():
dt = 100
endTime = 300
timeSensed = 0
droid.startSensingTimed(2,dt)
while timeSensed <= endTime:
senout = droid.sensorsReadAccelerometer().result
time.sleep(dt/1000.0)
timeSensed+=dt
print senout
clientsocket.send(str(senout).strip('[]'))
readAcc()
droid.stopSensing()
Output example:
1.8659877, 8.8259849999999993, 3.5412905000000001
This works fine if I want to read the values once, but I was wondering how I would go from here, I want to be able to use the values for controlling games and other applications.
Thanks for reading :)
My idea would be to first experiment with different motions of the device (say, a fast upward motion), gather the output values, and then simply trigger events (or whatever you need to trigger in a game) based on a specfic range of accelerometer values (similar movements should have similar value ranges).
I am trying to set the Performance Monitor User Mode Enable register on all cpus on a Nexus 4 running a mako kernel.
Right now I am setting the registers in a loadable module:
void enable_registers(void* info)
{
unsigned int set = 1;
/* enable user-mode access to the performance counter*/
asm volatile ("mcr p15, 0, %0, c9, c14, 0\n\t" : : "r" (set));
}
int init_module(void)
{
online = num_online_cpus();
possible = num_possible_cpus();
present = num_present_cpus();
printk (KERN_INFO "Online Cpus=%d\nPossible Cpus=%d\nPresent Cpus=%d\n", online, possible, present);
on_each_cpu(enable_registers , NULL, 1);
return 0;
}
The problem is that on_each_cpu only runs the function on Online cpus and as shown by the printk statment:
Online Cpus=1
Possible Cpus=4
Present Cpus=4
Only one of the four is online when I call on_each_cpu. So my question is, how do I force a cpu to be online, or how can force a certain cpu to execute code?
Thanks
You don't need to run the code on every cpu right now. What you need to do is arrange so that when the offline cpus come back online, your code is able to execute and enable the access to the PMU.
One way to achieve that would be with a cpu hotplug notifier.