Linux开发如何自主控制片选信号

在Linux开发中遇到要通过spi与芯片通讯的问题,Linux提供了spi的设备驱动,可以设置模式、频率、字节位长度,用Linux提供的spi的设备驱动在进行数据收发时,片选信号是:在发送数据前片选为高,发送和接收数据时片选拉低,数据收发完毕后片选拉高。而芯片要求片选信号是:在主机发送数据前片选为高,发送数据时片选拉低,数据发送完毕片选拉高,主机接收数据时片选拉低,接收完毕后片选再拉高。要按照这个时序来与芯片进行数据收发怎么办?若是单片机是可以自主控制片选引脚,但Linux开发如何自主控制片选信号?或是用别的什么办法?

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>

#include "spidev.h"

static void pabort(const char *s)
{
    perror(s);
    abort();
}

const char *device = "/dev/spidev0.0";
static uint8_t mode = 0;
static uint8_t bits = 8;
static uint32_t speed = 20000000;
static uint16_t delay;

static void transfer(int fd)
{
    int ret;
    uint8_t tx[] = {0x55,0x00,0x32,0x00,0x02,0x00,0x00,0xCF};
    uint8_t rx[30] = {0, };
    struct spi_ioc_transfer tr = {
        
        .tx_buf = (unsigned long)tx,
        .rx_buf = (unsigned long)rx,
        .len = 30,
        .delay_usecs = delay,
        .speed_hz = speed,
        .bits_per_word = bits,    
    };

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret == 1) {
         pabort("can't revieve spi message");
    }

    for (ret = 0; ret < tr.len; ret++) {
        printf("%x ",rx[ret]);
    }
    printf("\n");
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd;

    fd = open(device, O_RDWR);
    if (fd < 0)
        pabort("can't open device");

    /*
     * spi mode
     */
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
        pabort("can't set wr spi mode");

    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
        pabort("can't get spi mode");

    /*
     * bits per word
     */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't set bits per word");

    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't get bits per word");

    /*
     * max speed hz
     */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't set max speed hz");

    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't get max speed hz");

    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
    sleep (1);
    transfer(fd);

    close(fd);

    return ret;
}



#ifndef SPIDEV_H
#define SPIDEV_H

#include <linux/types.h>

#define SPI_CPHA        0x01
#define SPI_CPOL        0x02

#define SPI_MODE_0        (0|0)
#define SPI_MODE_1        (0|SPI_CPHA)
#define SPI_MODE_2        (SPI_CPOL|0)
#define SPI_MODE_3        (SPI_CPOL|SPI_CPHA)

#define SPI_CS_HIGH        0x04
#define SPI_LSB_FIRST        0x08
#define SPI_3WIRE        0x10
#define SPI_LOOP        0x20
#define SPI_NO_CS        0x40
#define SPI_READY        0x80

#define SPI_IOC_MAGIC            'k'


struct spi_ioc_transfer {
    __u64        tx_buf;
    __u64        rx_buf;

    __u32        len;
    __u32        speed_hz;

    __u16        delay_usecs;
    __u8        bits_per_word;
    __u8        cs_change;
    __u32        pad;

};

#define SPI_MSGSIZE(N) \
    ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
        ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])


/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
#define SPI_IOC_RD_MODE            _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE            _IOW(SPI_IOC_MAGIC, 1, __u8)

/* Read / Write SPI bit justification */
#define SPI_IOC_RD_LSB_FIRST        _IOR(SPI_IOC_MAGIC, 2, __u8)
#define SPI_IOC_WR_LSB_FIRST        _IOW(SPI_IOC_MAGIC, 2, __u8)

/* Read / Write SPI device word length (1..N) */
#define SPI_IOC_RD_BITS_PER_WORD    _IOR(SPI_IOC_MAGIC, 3, __u8)
#define SPI_IOC_WR_BITS_PER_WORD    _IOW(SPI_IOC_MAGIC, 3, __u8)

/* Read / Write SPI device default max speed hz */
#define SPI_IOC_RD_MAX_SPEED_HZ        _IOR(SPI_IOC_MAGIC, 4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ        _IOW(SPI_IOC_MAGIC, 4, __u32)



#endif /* SPIDEV_H */