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