I am attempting to send 16-bit messages from my beaglebone black on spidev1.0 (bus 1 device 0) to an IC chip TLV5618AC
The chip-select line needs to go from high to low before the shift registers start picking up bits on the falling edge of the clock.
I performed a modified version of spidev_test.c (the original worked fine). Since I need the chip select line to go from high to low between messages - the line ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); will not work because it transmits the data as a single message. Even if I put ioctl() within a for loop it would not work because it is the first and last message.
The following code works
static void transfer(int fd)
{
int ret;
unsigned short buffer[1];
int zero = 0;
FILE *iFile = fopen("firsttest.bin", "r");
if (iFile == NULL)
{
printf("Cannot open file \n");
exit(0);
}
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)zero,
.rx_buf = (unsigned long)zero,
.len = 2,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
while(!feof(iFile)){
fread(buffer,2,1,iFile);
unsigned short *tx = buffer;
unsigned short rx[1] = {0, };
tr.tx_buf = (unsigned long)tx;
tr.rx_buf = (unsigned long)rx;
int size = ARRAY_SIZE(tx);
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
for (ret = 0; ret < 1; ret++) {
printf("0x%04x\n", tx[ret]);
}
}
}
This second block of code does not
{
int ret;
unsigned short buffer[1];
int zero = 0;
FILE *iFile = fopen("firsttest.bin", "r");
if (iFile == NULL)
{
printf("Cannot open file \n");
exit(0);
}
struct spi_ioc_transfer tr[100];
unsigned short *p = (unsigned short*) calloc(100, sizeof(unsigned short));
unsigned short *p2 = (unsigned short*) calloc(100, sizeof(unsigned short));
while(!feof(iFile)){
unsigned short *tx = p2;
unsigned short *rx=p;
for(int j = 0; j< 100; j++){
fread(buffer,2,1,iFile);
tx = (unsigned short*) &buffer+j;
tr[j].tx_buf = (unsigned long)tx;
tr[j].rx_buf = 0;
tr[j].len = 2;/* Total length of message in bytes*/
tr[j].delay_usecs = delay;
tr[j].speed_hz = speed;
tr[j].bits_per_word = bits;
tr[j].cs_change = 1;
}
ret = ioctl(fd, SPI_IOC_MESSAGE(100), &tr);
if (ret < 1)
pabort("can't send spi message");
for(int v = 0; v<100; v++){
printf("0x%04x\n", rx);
}
}
free(p);
}
The second block of code yield this error
"can't send spi message: Invalid argument"
Since it is an invalid argument, I tried passing in '&tr' as well as 'tr' to no avail. Any input would be appreciated.
EDIT: So I resolved to use the first code which worked. I guess there is no reason to send large transfers. My system is fast enough to where the voltages are fast enough to effectively be real time!! Thanks for the help. (I also cleaned up my code a lot to make it easier to read!)
2 Answers 2
add memset(&tr, 0, sizeof(tr)); after struct spi_ioc_transfer tr
Comments
Looking through this, it occurs to me that you may not be defining your tr[j].rx_buf correctly, and this would lead to the invalid argument. There needs to be an allocated storage which I assume is *p, but you aren't associating that with the tr argument.
unsigned short buffer[1];, latertx = (unsigned short*) &buffer+j;. Well that won't work right unless j==0, len==1. You're accessing addresses you haven't allocated.