Raspberry Pi send data more than 1 byte (e.g. integer 1920) to Arduino by USB cable (serial) - interface

Currently, my project is to get a x coordination , cX value, from a webcam connected to raspberry pi 3B+, and send it to Arduino Uno. I successfully do the action when the integer is in range 0 to 255. Can I modify my code and send a larger integer, say up to 1920 to Arduino?
Here is part of my python code on raspi side:
import serial
import struct
while True:
...
cX = 248 //I want to send a larger number
print (cX)
ser.write(struct.pack('>H', cX))
...
Here is part of my c code on Arduino:
int cX = 0;
void setup()
{
...
Serial.begin(9600);
...
}
void loop()
{
if (Serial.available())
{
cX = Serial.read();
if (cX == 248)
{
//do something
}
}
}
Any help would be greatly appreciated

Try this on the Arduino side:
unsigned int cX = 0;
byte buffer[2] = {0};
size_t len = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{
len = Serial.readBytes(buffer, 2);
if (len == 2)
{
cX = (((int)buffer[0]) << 8) | buffer[1];
if (cX == 1920)
{
//do something
}
}
}
}
On the Python side, I don't know in detail, but from what I could see on the documentation, with the argument >H you should be sending an unsigned short (2 bytes size), big-endian, so it should work.

Related

Received Data Zeroed Out After Encountering First Byte Equal to Zero

Summarize the Problem:
I wrote a userspace SPI driver in linux for the NRF24L01+ transceiver. My goal is to send files to a server. A jetson nano is the sender, and a raspberry pi 3b+ the receiver. Both the spi and nano are running Linux.
I can consistently send packets and receive acknowledgements.
However, the issue is whenever I send a packet such as 0x ff ee dd 00 cc bb aa the receiver only receives the packet 0x ff ee dd 00 00 00 00. So what is happening is that whenever the first byte encountered is zero, the rest of the packet becomes zero. This causes the files I send to become corrupted.
I was able to reproduce this bug with a char array having a similar pattern. I noticed this trend when I printed out the file contents I was sending on the transmitter and receiver.
What I've tried:
I've tried altering my SPI read function. What I thought was happening was the chip select line was being flipped high early. This did not work, I got the same results.
I've printed the packets before calling the ioctl() function from the transmitter and the packet remains intact.
I've printed the return value of the ioctl() function to see how many bytes I was receiving and sending. I was sending 31 bytes from the transmitter, and receiving 32 bytes from the receiver. So it doesn't look like my reads and sends are failing.
If I had a logic analyzer my next step would be to check the SPI pins on the transmitter, but unfortunately I don't have one.
I've added a 10uF decoupling capacitor on the transceivers and that sped up communication.
Show Some Code:
Receiver side:
/**
* Reads the payload when data pipe
* is available.
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_rx_read(int spi_dev_fd, char * payload, int * pipe, int * bytes)
{
int pipe_temp, rtn;
// TODO: Add timeout.
do
{
rtn = nrf_rx_pipe_available(spi_dev_fd, &pipe_temp);
}while(rtn != 0);
if(rtn == 0)
{
char status;
if(bytes != NULL)
{
char size;
spi_read_msg(spi_dev_fd, R_RX_PL_WID, &status, &size, 1);
*bytes = (int) size;
}
spi_read_msg(spi_dev_fd, R_RX_PAYLOAD , &status, payload, (int) NUM_PAYLOAD_BYTES);
*pipe = pipe_temp;
char msg;
msg = RX_DR;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &msg, 1);
return 0;
}
return 1;
}
bool nrf_rx_pipe_available(int spi_dev_fd, int * pipe)
{
char addr = NOP;
char status;
spi_read_msg(spi_dev_fd, addr, &status, NULL, 0);
if((status & RX_DR) > 0)
{
*pipe = (status >> RX_P_NO) & 0x07;
if(*pipe > 5)
{
return 1;
}
return 0;
}
return 1;
}
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
string temp = string(recv_buffer);
temp = temp.substr(1);
strncpy(copy_to, temp.c_str(), len);
}
// debug code
for(int i = 0; i < len; ++i)
{
printf("copy_to: %x \n ", copy_to[i]);
}
// end debug code.
}
return res;
}
Transmitter side:
/**
* Function to load a payload and send a packet.
*
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_tx_send_packet(int spi_dev_fd, char * payload, int len)
{
int rtn;
// Put low so we can add the payload.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW);
// Set a new payload.
nrf_tx_new_payload(spi_dev_fd, payload, len);
// Start tx transmission.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_HIGH);
do
{
rtn = nrf_tx_pending_send(spi_dev_fd);
if(rtn == 2)
{
char clr = MAX_RT;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &clr, 1);
}
}while(rtn != 1);
// Go back to standby mode
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW); // Setting chip enable to 0.
char reg = W_REGISTER | STATUS;
char val = RX_DR | TX_DS | MAX_RT;
spi_send_msg(spi_dev_fd, reg, &val, 1);
return 0;
}
int spi_send_msg(int spi_dev_fd, char addr, char * data, int len)
{
char data_buffer[len + 1];
char recv_buffer;
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer[0] = addr;
for(int i = 1; i < len + 1; ++i)
{
data_buffer[i] = data[i-1];
printf("databuffer[i]: %x \n", data_buffer[i]);
}
xfer.tx_buf = (unsigned long) data_buffer;
xfer.rx_buf = (unsigned long) NULL;
xfer.len = len + 1;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
//xfer.rx_nbits = 8;
xfer.rx_nbits = 0;
xfer.tx_nbits = (8 * len) + 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
printf("res: %i \n", res);
return res;
}
I tried to add all the relevant code, sorry if it is a bit much. Main thing to look at is the send and receive functions. They all work as expected until I encounter the zeroed out byte.
If I am missing any information that can help someone out please let me know and I can add it. I think the send and receive functions are the most important however. I'm able to set and read the registers of the transceiver.
I can send files now!
The fix was done in spi_read_msg() function.
The problem was I was converting the buffer received to a string, which caused the data to be trimmed when the byte 0x00 was encountered. This is also equivalent to the null terminating character.
Receiver code:
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
for(int i = 0; i < len; ++i)
{
copy_to[i] = recv_buffer[i + 1];
}
}
}
return res;
}

linux device driver - ADS1292R problem in reading chip id on spi

I am novice to Linux device driver and writing driver module for TI-ADS1292R chip. This driver is loading without any error, creates character device entry in /dev directory. I am also able to transfer data on SPI bus (verified it on logic analyzer and DSO).
There are two problems here.
(1) in logic analyzer it shows that chip is responding with correct chip id (0x73) on read id command, but in my driver I am getting incorrect value (0x80). Why this is happening and where the problem is?
(2) As far as I understood, my driver should automatically loaded if I have configured it through defconfig file, which is not happening in my case. Right now, I am loading it as a built-in module with obj-y option.
My code has following snippets through which I am trying to read the chip id.
static int ads_send_byte(struct ads1292_chip *dev, int data)
{
int status;
struct spi_message msg = { };
struct spi_transfer transfer = { };
dev->tx_buff[0] = data;
transfer.tx_buf = dev->tx_buff;
transfer.rx_buf = dev->rx_buff;
transfer.len = 1;
transfer.speed_hz = SPI_BUS_SPEED;
spi_message_init(&msg);
spi_message_add_tail(&transfer, &msg);
status = spi_sync(dev->spi, &msg);
printk(KERN_DEBUG "ecg: %s (%#x) %d\n", __func__, data, status);
return status;
};
static int ads_send_RREG(struct ads1292_chip *dev, char __user * buf, u8 reg, u8 size)
{
struct spi_message msg = { };
struct spi_transfer transfer = { };
int ret;
dev->tx_buff[0] = ADS1292_RREG | reg;
dev->tx_buff[1] = size - 1; // datasheet: no of regs - 1
memset(dev->rx_buff, 0, size);
memset(dev->tx_buff + 2, 0, size);
transfer.speed_hz = SPI_BUS_SPEED;
transfer.tx_buf = dev->tx_buff;
transfer.rx_buf = dev->rx_buff;
transfer.len = size + 2; // 2 is for command tx
transfer.delay_usecs = 40; // datasheet: 4 clocks after each message
transfer.cs_change = 1; // Always toggle CS line after transfer
spi_message_init(&msg);
spi_message_add_tail(&transfer, &msg);
ret = spi_sync(dev->spi, &msg);
//printk(KERN_DEBUG "ecg: %s %x\n", __func__, dev->rx_buff[0]);
if (unlikely(ret))
return ret;
ret = copy_to_user(buf, dev->rx_buff, size);
return ret;
}
static int ads_cdev_open(struct inode *inode, struct file *filp)
{
struct ads1292_dev *ads = container_of(inode->i_cdev, struct ads1292_dev, dev);
char buff[1];
printk(KERN_DEBUG "ecg: %s\n", __func__);
filp->private_data = ads;
gpio_set_value_cansleep(ads1292_gpio_start.gpio, 0);
ads_send_byte(&ads->chip, ADS1292_RESET);
mdelay(1);
ads_send_byte(&ads->chip, ADS1292_SDATAC);
mdelay(10);
ads_send_RREG(&ads->chip, buff, ADS1292_ID, 1);
printk(KERN_DEBUG "ecg: ID - %x\n", buff[0]);
return 0;
}

X1, X2, X4 encoding for encoders in Arduino

So, I'm coding for an encoder in Arduino and I'm not sure what type of encoding I'm using in my code. I'm also curious how X1, X2 and X4 encoding would look like in the arduino code. Below is the code that I used.
#include <SoftwareSerial.h>
#define outputA 5 //channel A
#define outputB 6 //channel B
int counter = 0;
int degree = 0;
int aState;
int aLastState;
encoderPPR = 2048 //real ppr*2
void setup() {
pinMode (outputA, INPUT_PULLUP);
pinMode (outputB, INPUT_PULLUP);
Serial.begin(9600);
//Reads the initial state of the outputA
aLastState = digitalRead(outputA);
}
void loop(){
aState = digitalRead(outputA); //reads the 'current' state of the outputA
if (aState != aLastState) { //if there's a shift (perubahan)
if (digitalRead(outputB) != aState) {
counter ++;
} else {
counter --;
}
if (counter > encoderPPR or counter < -encoderPPR)
{
counter = 0;
}
}
derajat = counter * 360 / encoderPPR;
aLastState = aState;
}
}
This is the code that I used. Is the encoding used in the code above X2 or X4 because I'm not sure myself. Thank you.

Serial communication with jSerialComm not sending anything

I built a simple Scala application and a simple Arduino script to test serial communication on the jSerialComm library. The program only finds one active port (the one the Arduino connected to), the baud rates are the same on the port and the Arduino and the code throws no exceptions while writing. The Arduino, however, receives nothing (the RX led is off).
The Scala code:
import com.fazecast.jSerialComm._
object Test extends App {
val ports = SerialPort.getCommPorts
ports.foreach(println(_))
val port: SerialPort = ports(0)
var bytes = Array[Byte]()
val toWrite: Long = 3
var a = 0
var b = 0
var c = 0
println(port.getBaudRate)
while (true) {
if (a < 3) a += 1 else a = 0
bytes = Array[Byte](a.toByte, a.toByte, a.toByte)
port.writeBytes(bytes, toWrite)
println("Sent " + bytes(0) + " to " + port.toString)
Thread.sleep(1000)
}
}
The Arduino code:
const int R = 12;
const int G = 13;
const int B = 11;
void setup() {
pinMode(R, OUTPUT);
pinMode(G, OUTPUT);
pinMode(B, OUTPUT);
Serial.begin(9600);
while(!Serial);
}
void loop() {
byte buff[3] = {0, 0, 0};
int numR = 0;
bool cont1 = false;
bool cont2 = false;
bool cont3 = false;
if(Serial.available()){
Serial.print("Found stuff");
Serial.readBytes(buff,3);
}
for(int i = 0; i < 3; i++){
if(buff[i] == 1){
cont1 = true;
}
if(buff[i] == 2){
cont2 = true;
}
if(buff[i] == 3){
cont3 = true;
}
}
if(cont1) digitalWrite(R, HIGH); else digitalWrite(R, LOW);
if(cont2) digitalWrite(G, HIGH); else digitalWrite(G, LOW);
if(cont3) digitalWrite(B, HIGH); else digitalWrite(B, LOW);
if(cont1 || cont2 || cont3) delay(1000);
}
I had forgotten to open the port with
port.openPort()
Now it works just fine

Get Xbee response from Serial and send to a browser

I am trying to do some experiments with Arduino, Ethernet Shield and Xbee Shield.
I demonstrate my set up board like this:
Group 1: Arduino Uno + Xbee shield : broadcast the signal
Group 2: Arduino Uno + Xbee shield + Ethernet shield: receive the signal from
group 1, get the signal strength from AT command and print it into the browser.
The problem here is I can't get the result after sending to the Serial my ATDB command, actually, I am not sure it did worked as I expected.
Here is the code that I used to retrieve the signal strength.
int data;
void setup()
{
Serial.begin(9600);
}
void receiver_checker(){
delay(1200);
Serial.print("+++");
delay(1200);
bool bOK = false;
while (Serial.available() > 0) {
Serial.write(Serial.read());
bOK = true;
}
if(bOK)
{
Serial.println();
Serial.println("ATDB");
delay(100);
while (Serial.available() > 0) {
Serial.write(Serial.read());
}
Serial.println();
}
Serial.println();
}
void loop()
{
while(Serial.available() > 0){
data = Serial.read();
if(data == '1'){
// Broadcaster 1
//Serial.println("1------------------");
receiver_checker();
}
}
}
This part worked as I expected, it printed out in hex number the signal strength of the last package that it received.
Here is the code I combined the previous one and the server part from Web Server tutorial:
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xCA, 0xFE, 0x00, 0x00, 0x00, 0x02
};
IPAddress ip(1, 1, 1, 2);
int data;
int count = 0;
char result;
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
// Serial.print("server is at ");
// Serial.println(Ethernet.localIP());
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
// Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
data = Serial.read();
// if it's a capital H (ASCII 72), turn on the LED:
if (data == '1') {
count += 1;
client.print("The number of times:");
client.print(count);
result = receiver_checker();
client.print("========================");
client.print(result);
client.print("========================");
}
}
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
char receiver_checker(){
char signal;
delay(1200);
Serial.print("+++");
delay(1200);
bool bOK = false;
while (Serial.available() > 0) {
Serial.write(Serial.read());
bOK = true;
}
if(bOK)
{
Serial.println();
Serial.println("ATDB");
delay(100);
while (Serial.available() > 0) {
signal = Serial.read();
}
Serial.println();
}
Serial.println();
return signal;
}
If there is another way to interact with the Xbee shield not go through Serial like I ask and get response directly, please let me know!
Your receiver_checker() function is reading characters back from the XBee module, and just returning the last character received, which is likely a carriage return or line feed.
Update the function to return an int, and replace your while (Serial.available() > 0) with the following:
signal = (int) strtoul(Serial.readString().c_str(), 0, 16);
That's for when the XBee returns a hexadecimal value. If it's returning a decimal value, change the 16 parameter to a 10.