I am building a program in Common Lisp, which communicates via i2c to a pca9685 using sysfs on a raspberry pi 3B+.
When initializing the device, I need to select the pca by using (ioctl fd +i2c-slave+ addr)
where +i2c-slave+ = xf0703
(command for selecting slave) and addr = 0x40
(for pca9685)
However from the call I get an error:
IOCTL 1795 failed: Invalid argument
[Condition of type SIMPLE-ERROR]
0: ((SETF I2C::IOCTL) 64 10 1795)
1: (I2C:I2C-START #S(I2C:I2C-DEV :FILENAME "/dev/i2c-1" :DEV 1 :ADDR 64))
I am using the ioctl implementation from cl-spidev.
Since I am on sbcl, the relevant function is
(defun (setf ioctl) (arg fd cmd)
(sb-alien:with-alien ((value sb-alien:int))
(setf value arg)
(multiple-value-bind (wonp error)
(sb-unix:unix-ioctl (stream-fd fd)
(if (< cmd (expt 2 31)) cmd (- cmd (expt 2 32)))
(sb-alien:alien-sap (sb-alien:addr value)))
(unless wonp
(error "IOCTL ~a failed: ~a" cmd (sb-impl::strerror error))))
arg))
and it is called like this
(setf (ioctl fd cl-i2c-lli:+i2c-slave+) addr)
My current guess is that the ioctl function is passing a pointer, while it should be a plain long (according to the docs), but still am unable to wrap my head around it completely. Am I missing something obvious?
The Adafruit python library, and some example C implementations work in the same way.
Notes
I2C_SLAVE_FORCE
, and got the same result.i2cdetect
confirms that there is a device on #x40
, successfully read some registers with i2cget
.Your supposition is correct, this wrapper function that you are using calls ioctl
with a pointer to your value instead of the value.
Have you tried simply (sb-unix:unix-ioctl fd cl-i2c-lli:+i2c-slave+ addr)
?