Port-arm archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: SPI on RPI



pouya+lists.netbsd%nohup.io@localhost (Pouya Tafti) writes:

>And I did what seemed reasonable based on reading the spi(4) manpage, to send through some data of length slen bytes pointed at by sbuf:

>	struct spi_ioctl_transfer spt;
>	int fd, r;

>        spt.sit_addr = 0;
>	spt.sit_send = sbuf;
>	spt.sit_sendlen = slen;

>	fd = open("/dev/spi0, O_RDWR);
>	r = ioctl(fd, SPI_IOCTL_TRANSFER, &spt);

>But my test program simply stops responding after initiating the transfer.

You need to initialize sit_recv and sit_recvlen as well.

Here is an example. Most SPI devices use a separate data/command
line, here GPIO25 that must be configured as output (with DTB or
/etc/gpio.conf). Many chips allow reading back data or status
information, but real-world devices don't support it.


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <errno.h>
#include <string.h>

#include <sys/endian.h> 
#include <sys/ioctl.h>
#include <sys/gpio.h> 
#include <dev/spi/spi_io.h>

#define GPIO "/dev/gpio0"
#define PIN_SELECT 25

#define SPI "/dev/spi0"
#define MODE 0
#define SPEED 10000000
#define ADDR 0

typedef struct {
	int gfd;
	int sfd;
	int select_pin;
	int addr;
} tft_t;

int
gpio_set(int fd, int pin, int val)
{
        struct gpio_req gp;

        gp.gp_name[0] = '\0';
        gp.gp_pin = pin;
        gp.gp_value = val;

        if (ioctl(fd, GPIOWRITE, &gp) == -1)
                return errno;
        return 0;
}

int
spi_configure(int fd, int addr, uint32_t mode, uint32_t speed)
{
        spi_ioctl_configure_t sic;

        sic.sic_addr = addr;
        sic.sic_mode = mode;
        sic.sic_speed = speed;

        if (ioctl(fd, SPI_IOCTL_CONFIGURE, &sic) == -1)
                return errno;
        return 0;
}

int
spi_transfer(int fd, int addr, void *send, size_t slen, void *recv, size_t rlen)
{
        spi_ioctl_transfer_t sit;

        sit.sit_addr = addr;
        sit.sit_send = send;
        sit.sit_sendlen = slen;
        sit.sit_recv = recv;
        sit.sit_recvlen = rlen;

        if (ioctl(fd, SPI_IOCTL_TRANSFER, &sit) == -1)
                return errno;
        return 0;
}

void
read_data(tft_t *tft, uint8_t *buf, size_t cnt)
{

        gpio_set(tft->gfd, tft->select_pin, GPIO_PIN_HIGH);
        spi_transfer(tft->sfd, tft->addr, NULL, 0, buf, cnt);
}

void
write_data(tft_t *tft, uint8_t *buf, size_t cnt)
{

        gpio_set(tft->gfd, tft->select_pin, GPIO_PIN_HIGH);
        while (cnt > 0) {
                size_t chunk = cnt > 4095 ? 4095 : cnt;
                spi_transfer(tft->sfd, tft->addr, buf, chunk, NULL, 0);
                buf += chunk;
                cnt -= chunk;
        }
}

void
write_command(tft_t *tft, uint8_t cmd, uint8_t *status)
{

        gpio_set(tft->gfd, tft->select_pin, GPIO_PIN_LOW);
        spi_transfer(tft->sfd, tft->addr, &cmd, 1, NULL, 0);
        if (status)
                spi_transfer(tft->sfd, tft->addr, NULL, 0, &status, 1);
}

void
read_command(tft_t *tft, uint8_t cmd, uint8_t *buf, size_t cnt)
{

        gpio_set(tft->gfd, tft->select_pin, GPIO_PIN_LOW);
        spi_transfer(tft->sfd, tft->addr, &cmd, 1, NULL, 0);
        gpio_set(tft->gfd, tft->select_pin, GPIO_PIN_HIGH);
        spi_transfer(tft->sfd, tft->addr, NULL, 0, buf, cnt);
}

int main()
{
	tft_t T;
	char buf[] = "Hello world";

	T.gfd = open(GPIO, O_RDWR);
	T.sfd = open(SPI, O_RDWR);
        T.select_pin = PIN_SELECT;
        T.addr = ADDR;

        gpio_set(T.gfd, T.select_pin, GPIO_PIN_HIGH);
        spi_configure(T.sfd, T.addr, MODE, 0);
        spi_configure(T.sfd, T.addr, MODE, SPEED);

	/* send byte 0x00 as command, don't read back a status byte */
	write_command(&T, 0x00, NULL);

	/* send text as data */
	write_data(&T, buf, strlen(buf));

	close(T.sfd);
	close(T.gfd);

	return 0;
}




Home | Main Index | Thread Index | Old Index