LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   SPI program using c++ (https://www.linuxquestions.org/questions/programming-9/spi-program-using-c-857237/)

Lobinho 01-19-2011 05:19 AM

SPI program using c++
 
1 Attachment(s)
Hi all,

I'm trying to build a spi program using c++. I'm able to perform half-duplex transfers using the read/write functions, it works perfectly.

Now I need to perform a full-duplex transfer, but I'm facing some problems.
When I try to receive more than one byte, the slave returns to me only one byte.

Ex:

I send: FF FF FF FF FF
The slave must return: 03 02 00 13 04

But what is happening is:

1st Transfer:
tx: FF FF FF FF FF
rx: 03 00 00 00 00

2nd Transfer:
tx: FF FF FF FF FF
rx: 02 00 00 00 00

3rd Transfer:
tx: FF FF FF FF FF
rx: 00 00 00 00 00

...
I need to perform 5 transfers to read my 5 bytes... :/

It's so strange, it's look like the spi driver try to receive only one byte.

I based my code on an example code found on kernel Docs (the complete file is attached).

The transfer routine is here:
Code:

static void transfer(int fd)
{
        int ret;
        uint8_t tx[] = {
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        };
        uint8_t rx[ARRAY_SIZE(tx)] = {0, };
        printf("Criando estrutura de transferência\n");
        printf("TX (%d): \n", ARRAY_SIZE(tx));
        printBuffer(tx, ARRAY_SIZE(tx));
        printf("RX (%d):\n", ARRAY_SIZE(rx));
        printBuffer(rx, ARRAY_SIZE(rx));
        struct spi_ioc_transfer tr = {
                tr.tx_buf = (unsigned long)tx,
                tr.rx_buf = (unsigned long)rx,
                tr.len = ARRAY_SIZE(tx),
                tr.delay_usecs = delay,
                tr.speed_hz = speed,
                tr.bits_per_word = bits,
        };

        printf("Enviando dados \n");
        ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
        if (ret == 1)
                pabort("can't send spi message");
        if (ret < 0)
                perror("Error - ");

        printf("Imprimindo resposta\n");
        printf("Buffer de envio: %d\n", ARRAY_SIZE(tx));
        printf("Buffer de resposta: %d\n", ARRAY_SIZE(rx));
        printf("TX (%d): \n", ARRAY_SIZE(tx));
        printBuffer(tx, ARRAY_SIZE(tx));
        printf("RX (%d):\n", ARRAY_SIZE(rx));
        printBuffer(rx, ARRAY_SIZE(rx));

        puts("");
}


Someone knows how to help me?
Thanks in advance

Lobinho 01-19-2011 12:20 PM

I think I have to deassert the CS pin between a transfer, so I tried to use the option:

Code:

tr.cs_change = true,
Taken from spidev.h:

* @cs_change: True to deselect device before starting the next transfer.


My pc is attached to a LPC uC, so with help of an oscilloscope I detected that CS (chip select) is not changing his state during the transfer.

I don't know if this is a kernel bug or I'm missing something.

gsinde 02-08-2011 11:21 AM

Well, I have been seeing no SPI traffic with your code above so I changed the transfer routine a little. When I set all of the spi_ioc_transfer parameters (speed, delay, etc.), no data comes out my SPI bus. However, when I memset the struct to all zeros and just set the three parameters I care about, it works fine. Not sure why yet.

#define SPI_IOC_TRANSFER ((IOC_WRITE << 30) | ((sizeof(struct spi_ioc_transfer)) << 16) | ('k' << 8) | 0)
#define SPI_IOC_SET_MODE ((IOC_WRITE << 30) | (1 << 16) | ('k' << 8) | 1)
#define SPI_IOC_JUSTIFY ((IOC_WRITE << 30) | (0 << 16) | ('k' << 8) | 2)
#define SPI_IOC_SET_BITS ((IOC_WRITE << 30) | (1 << 16) | ('k' << 8) | 3)
#define SPI_IOC_SET_SPEED ((IOC_WRITE << 30) | (4 << 16) | ('k' << 8) | 4)

void BasicSpidev::Transfer(uint8_t *command, uint8_t *response, uint32_t len)
{
struct spi_ioc_transfer xfer;

if (fspi >= 0)
{
if (len)
{
memset((void *)&xfer, 0, sizeof(struct spi_ioc_transfer));
xfer.tx_buf = (uint64_t) command;
xfer.rx_buf = (uint64_t) response;
xfer.len = len;

ioctl(fspi, SPI_IOC_TRANSFER, &xfer);
}
}
}

Lobinho 02-10-2011 05:18 PM

Hi gsinde,

When you declare the struct, theres no guarantee that the struct is cleaned. I think that theres no relation with set speed or mode.

On linux Docs theres some examples for SPI program:
http://www.mjmwired.net/kernel/Documentation/spi/spidev
http://www.kernel.org/doc/Documentation/spi/

spidev_test.c works fine my pc ;)


My problem was with mode configuration. I was using polarity = 0 phase = 0, and my device was using other mode configuration.

Any other doubt post here.


All times are GMT -5. The time now is 04:39 PM.