OK. I’ll give it a try. Thanks.
That did it!!! Thanks.
Here’s the change I made in Julia (per your suggestion).
function spi_open(spi::SPIDevice)
#cout << "Opening the file: " << filename.c_str() << endl;
O_RDWR = 0x0002 # open for reading and writing
fd = ccall((:open, "libc"), Cint, (Cstring, Cint), spi.filename, O_RDWR)
if (fd < 0)
error("SPI: Can't open device.")
return fd
end
spi.file = fd
return 0
end
Here’s the results (step by step):
julia> include("spidev_h.jl")
julia> include("spidev.jl")
spidev
julia> import spidev
julia> using spidev
julia> function combineValues(upper::UInt8, lower::UInt8)
return (Int16(upper) << 8) | Int16(lower)
end
combineValues (generic function with 1 method)
julia> println("Starting RPi SPI ADC Example")
Starting RPi SPI ADC Example
julia> spi = spidev.SPIDevice(0,0)
spidev.SPIDevice(0x00, 0x00, 0, "/dev/spidev0.0", 0x03, 0x08, 0x00077240, 0x0000)
julia> ret = spidev.spi_open(spi)
0
julia> spi.file
20
julia> ret = spidev.spi_setMode(spi, UInt8(SPI_MODE_0))
0
julia> ret = spidev.spi_setBitsPerWord(spi, UInt8(8))
0
julia> ret = spidev.spi_setSpeed(spi, UInt32(1000000)) # Have access to SPI Device object
0
julia> println("The SPI ADC is setup")
The SPI ADC is setup
julia> send = [0b00000001, 0b10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
8-element Array{UInt8,1}:
0x01
0x80
0x00
0x00
0x00
0x00
0x00
0x00
julia> spi
spidev.SPIDevice(0x00, 0x00, 20, "/dev/spidev0.0", 0x00, 0x08, 0x000f4240, 0x0000)
julia> receive = [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
8-element Array{UInt8,1}:
0x00
0x00
0x00
0x00
0x00
0x00
0x00
0x00
julia> len = 3
3
julia> transfer = spi_ioc_transfer()
spi_ioc_transfer(0x0000000067b8bb24, 0x0000000000015007, 0x00000000, 0x00000046, 0xbb20, 0xb8, 0x67, 0x00, 0x00, 0x0000)
julia> #see <linux/spi/spidev.h> for details!
transfer.tx_buf = pointer(send)
Ptr{UInt8} @0x681f0fb0
julia> transfer.rx_buf = pointer(receive)
Ptr{UInt8} @0x6f482090
julia> transfer.len = len #number of bytes in vector
3
julia> transfer.speed_hz = spi.speed
0x000f4240
julia> transfer.delay_usecs = spi.delay
0x0000
julia> transfer.bits_per_word = spi.bits
0x08
julia> transfer.pad = 0
0
julia> transfer
spi_ioc_transfer(0x00000000681f0fb0, 0x000000006f482090, 0x00000003, 0x000f4240, 0x0000, 0x08, 0x67, 0x00, 0x00, 0x0000)
julia> spi.file
20
julia> ret = ccall((:ioctl, "libc"), Cint, (Cint, Clong, Ref{spi_ioc_transfer}), spi.file, SPI_IOC_MESSAGE(1), transfer)
3
julia> receive
8-element Array{UInt8,1}:
0x00
0x01
0x08
0x00
0x00
0x00
0x00
0x00
julia> value = combineValues(receive[2] & 0b00000011, receive[3])
264
julia> println("This is the value " * string(value) * " out of 1024.")
This is the value 264 out of 1024.
julia> println("End of ERPi SPI ADC Example")
End of ERPi SPI ADC Example
OK. So, in my spi_transfer() function - how do I make sure that the receive array retains its values? Di I use an unsafe_wrap routine?
function spi_transfer(spi::SPIDevice, send::Array{UInt8,1}, receive::Array{UInt8, 1}, len::Int32)
transfer = spi_ioc_transfer()
#see <linux/spi/spidev.h> for details!
transfer.tx_buf = pointer(send)
transfer.rx_buf = pointer(receive)
transfer.len = len #number of bytes in vector
transfer.speed_hz = spi.speed
transfer.delay_usecs = spi.delay
transfer.bits_per_word = spi.bits
transfer.pad = 0
ret = ccall((:ioctl, "libc"), Cint, (Cint, Clong, Ref{spi_ioc_transfer}...), spi.file, SPI_IOC_MESSAGE(1), transfer)
if (ret < 0)
error("SPI: Transfer SPI_IOC_MESSAGE Failed")
return -1
end
return ret
end
One thing more to add (and probably goes to how to retrieve data back from the buffers). How do I get the pointers back?
before the struct gets passed to ioctl:
julia> #see <linux/spi/spidev.h> for details!
transfer.tx_buf = pointer_from_objref(send)
Ptr{Void} @0x6f54fd30
julia> transfer.rx_buf = pointer_from_objref(receive)
Ptr{Void} @0x66d882b0
And, after the ioctl call:
julia> ret = ccall((:ioctl, "libc"), Cint, (Cint, Clong, Ref{spi_ioc_transfer}...), spi.file, SPI_IOC_MESSAGE(1), transfer)
3
julia> transfer.tx_buf
0x000000006f54fd30
julia> transfer.rx_buf
0x0000000066d882b0
The numbers are the same, but the tx_buf and rx_buf are just UInt64 numbers, now - not pointers.
OK. I’ve had a chance to get back to this and even though I am able to make a legitimate ioctl call for the SPI transfer, I’m not getting the correct return array (and by the simulation - I’m not sure the right values are even going in.
So, here is the code for the simulated ioctl shared library. I’d ask that someone please be sure I am casting values correctly. You’ll notice that I print the contents for the tx and rx arrays before and after the ioctl call. The problem is - the data doesn’t look correct going in - so naturally it will be wrong coming out.
#include <iostream>
#include <cstdio>
#include <fcntl.h>
#include <errno.h>
/* Not technically required, but needed on some UNIX distributions */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
int fd_is_valid(int fd)
{
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
extern "C" {
int simioctl(int fd, unsigned long cmd, unsigned long arg)
{
struct spi_ioc_transfer *ioc;
ioc = (struct spi_ioc_transfer *) arg;
int fdChk = fd_is_valid(fd);
printf("fd_is_valid(fd): %d\n", fdChk);
//if ((file = ::open("/dev/spidev0.0", O_RDWR))<0){
// perror("SPI: Can't open device.");
// return -1;
// }
unsigned char *tx = (unsigned char *) ioc->tx_buf;
unsigned char *rx = (unsigned char *) ioc->rx_buf;
printf("fd: %d\n", fd);
printf("cmd: %lX\n", cmd);
printf("spi_ioc_transfer arg\n\n");
printf("address of tx_buf: %llX\n", ioc->tx_buf);
printf("address of rx_buf: %llX\n", ioc->rx_buf);
printf("ioc->len: %d\n", ioc->len);
printf("ioc->speed_hz: %d\n", ioc->speed_hz);
printf("ioc->delay_usecs: %d\n", ioc->delay_usecs);
printf("ioc->bits_per_word: %d\n", ioc->bits_per_word);
printf("ioc->pad: %d\n", ioc->pad);
int size_tx_buf = sizeof(ioc->tx_buf);
printf("tx before ioctl\n");
for (int i = 0; i < size_tx_buf; i++)
printf("%X\n", tx[i]);
printf("rx before ioctl\n");
for (int i = 0; i < size_tx_buf; i++)
printf("%X\n", rx[i]);
int status = ioctl(fd, cmd, arg);
if (status < 0) {
perror("SPI: Transfer SPI_IOC_MESSAGE Failed");
return status;
}
printf("tx after ioctl\n");
for (int i = 0; i < size_tx_buf; i++)
printf("%X\n", tx[i]);
printf("rx after ioctl\n");
for (int i = 0; i < size_tx_buf; i++)
printf("%X\n", rx[i]);
return 1;
}
}
Here’s the Julia run:
julia> include("spidev_h.jl")
julia> include("spidev.jl")
spidev
julia> import spidev
julia> using spidev
julia> function combineValues(upper::UInt8, lower::UInt8)
return (Int16(upper) << 8) | Int16(lower)
end
combineValues (generic function with 1 method)
julia> println("Starting RPi SPI ADC Example")
Starting RPi SPI ADC Example
julia> spi = spidev.SPIDevice(0,0)
spidev.SPIDevice(0x00, 0x00, 0, "/dev/spidev0.0", 0x03, 0x08, 0x00077240, 0x0000)
julia> ret = spidev.spi_open(spi)
0
julia> ret = spidev.spi_setSpeed(spi, UInt32(1000000)) # Have access to SPI Device object
0
julia> ret = spidev.spi_setMode(spi, UInt8(SPI_MODE_0))
0
julia> ret = spidev.spi_setBitsPerWord(spi, UInt8(8))
0
julia> println("The SPI ADC is setup")
The SPI ADC is setup
julia> send = Array{UInt8, 1}(8)
8-element Array{UInt8,1}:
0x30
0xeb
0xc9
0x67
0x00
0x00
0x00
0x00
julia> send = zeros(send)
8-element Array{UInt8,1}:
0x00
0x00
0x00
0x00
0x00
0x00
0x00
0x00
julia> send[1] = 0b00000001 # The Start Bit followed
0x01
julia> # Set the SGL/Diff and D mode -- e.g., 1000 means single ended CH0 value
send[2] = 0b10000000 # The MSB is the Single/Diff bit and it is followed by 000 for CH0
0x80
julia> send[3] = 0 # This byte doesn't need to be set, just for a clear display
0
julia> receive = Array{UInt8, 1}(8)
8-element Array{UInt8,1}:
0x00
0x63
0x7b
0x71
0x50
0x38
0x6e
0x71
julia> receive = zeros(receive)
8-element Array{UInt8,1}:
0x00
0x00
0x00
0x00
0x00
0x00
0x00
0x00
julia> len = 3
3
julia> transfer = spi_ioc_transfer()
spi_ioc_transfer(0x0000000067ba6e54, 0x0000000000015007, 0x00000000, 0x00000000, 0x6e50, 0xba, 0x67, 0x00, 0x00, 0x0000)
julia> transfer.tx_buf = pointer_from_objref(send)
Ptr{Void} @0x6f6b1db0
julia> transfer.rx_buf = pointer_from_objref(receive)
Ptr{Void} @0x6f7a0430
julia> tempRx_buf = pointer_from_objref(receive)
Ptr{Void} @0x6f7a0430
julia> transfer.len = len #number of bytes in vector
3
julia> transfer.speed_hz = spi.speed
0x000f4240
julia> transfer.delay_usecs = spi.delay
0x0000
julia> transfer.bits_per_word = spi.bits
0x08
julia> transfer.pad = 0
0
julia> ret = ccall((:simioctl, "/home/julia-user/julia-0.6.0/bin/libsimioctl.so"), Cint, (Cint, Clong, Ref{spi_ioc_transfer}), spi.file, SPI_IOC_MESSAGE(1), transfer)
fd_is_valid(fd): 1
fd: 18
cmd: 40206B00
spi_ioc_transfer arg
address of tx_buf: 6F6B1DB0
address of rx_buf: 6F7A0430
ioc->len: 3
ioc->speed_hz: 1000000
ioc->delay_usecs: 0
ioc->bits_per_word: 8
ioc->pad: 0
tx before ioctl
F0
1D
6B
6F
8
0
0
0
rx before ioctl
70
4
7A
6F
8
0
0
0
tx after ioctl
F0
1D
6B
6F
8
0
0
0
rx after ioctl
0
1D
5C
6F
8
0
0
0
1
julia> send
8-element Array{UInt8,1}:
0x01
0x80
0x00
0x00
0x00
0x00
0x00
0x00
julia> receive
8-element Array{UInt8,1}:
0x02
0x00
0x00
0x00
0x04
0x00
0x00
0x00
pointer
OK. Thanks. I’m going to award you a sainthood for patience with me!
Consistently, working! Yahoo!
Here’s a link to a demonstration of using SPI (pure Julia) to communicate between a Raspberry Pi and a MCP3008 chip (to get analog values from a potentiometer).