• 和菜鸟一起学linux总线驱动之初识spi驱动数据传输流程


           对于SPI的一些结构体都有所了解之后呢,那么再去瞧瞧SPI的那些长见的操作的函数了。

    首先看一下本人画的比较挫的数据流了,仅供参考,如有不对,不吝赐教

     

     

    接下来看看各个函数吧还是:

     

    SPI write

     

    /**
     * spi_write - SPI synchronous write
     * @spi: device to which data will be written
     * @buf: data buffer
     * @len: data buffer size
     * Context: can sleep
     *
     * This writes the buffer and returns zero or a negative error code.
     * Callable only from contexts that can sleep.
     */
    static inline int
    spi_write(struct spi_device *spi, const void *buf, size_t len)
    {
           struct spi_transfer   t = {
                         .tx_buf           = buf,
                         .len         = len,
                  };
           struct spi_message  m;
     
           spi_message_init(&m);
           spi_message_add_tail(&t, &m);
           return spi_sync(spi, &m);
    
    }
    
    


    SPI发送函数,数据放在buf中,然后把要发送的数据放在工作队列中

     

    SPI  read

     

    /**
     * spi_read - SPI synchronous read
     * @spi: device from which data will be read
     * @buf: data buffer
     * @len: data buffer size
     * Context: can sleep
     *
     * This reads the buffer and returns zero or a negative error code.
     * Callable only from contexts that can sleep.
     */
    static inline int
    spi_read(struct spi_device *spi, void *buf, size_t len)
    {
           struct spi_transfer   t = {
                         .rx_buf           = buf,
                         .len         = len,
                  };
           struct spi_message  m;
    
           spi_message_init(&m);
           spi_message_add_tail(&t, &m);
           return spi_sync(spi, &m);
    }
    
    


    SPI接收函数,数据放在buf中,然后把要发送的数据放在工作队列中,发送出去

     

    SPI write 8 bits read 8 bits

     

    /* this copies txbuf and rxbuf data; for small transfers only! */
    extern int spi_write_then_read(struct spi_device *spi,
                  const void *txbuf, unsigned n_tx,
                  void *rxbuf, unsigned n_rx);
    /**
     * spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
     * @spi: device with which data will be exchanged
     * @cmd: command to be written before data is read back
     * Context: can sleep
     *
     * This returns the (unsigned) eight bit number returned by the
     * device, or else a negative error code.  Callable only from
     * contexts that can sleep.
     */
    static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
    {
           ssize_t                   status;
           u8                  result; 
           status = spi_write_then_read(spi, &cmd, 1, &result, 1);
    
           /* return negative errno or unsigned value */
           return (status < 0) ? status : result;
    }
    

     

     

    SPI write 8 bit read 16 bits

     

    /**
     * spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read
     * @spi: device with which data will be exchanged
     * @cmd: command to be written before data is read back
     * Context: can sleep
     *
     * This returns the (unsigned) sixteen bit number returned by the
     * device, or else a negative error code.  Callable only from
     * contexts that can sleep.
     *
     * The number is returned in wire-order, which is at least sometimes
     * big-endian.
     */
    static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
    {
           ssize_t                   status;
           u16                result;
     
           status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);
     
           /* return negative errno or unsigned value */
           return (status < 0) ? status : result;
    }
    
    

     

    int spi_write_then_read(struct spi_device *spi,
                  const void *txbuf, unsigned n_tx,
                  void *rxbuf, unsigned n_rx)
    {
           static DEFINE_MUTEX(lock);
     
           int                 status;
           struct spi_message  message;
           struct spi_transfer   x[2];
           u8                  *local_buf;
     
           /* Use preallocated DMA-safe buffer.  We can't avoid copying here,
            * (as a pure convenience thing), but we can keep heap costs
            * out of the hot path ...
            */
           if ((n_tx + n_rx) > SPI_BUFSIZ)
                  return -EINVAL;
     
           spi_message_init(&message);
           memset(x, 0, sizeof x);
           if (n_tx) {
                  x[0].len = n_tx;
                  spi_message_add_tail(&x[0], &message);
           }
           if (n_rx) {
                  x[1].len = n_rx;
                  spi_message_add_tail(&x[1], &message);
           }
     
           /* ... unless someone else is using the pre-allocated buffer */
           if (!mutex_trylock(&lock)) {
                  local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
                  if (!local_buf)
                         return -ENOMEM;
           } else
                  local_buf = buf;
     
           memcpy(local_buf, txbuf, n_tx);
           x[0].tx_buf = local_buf;
           x[1].rx_buf = local_buf + n_tx; 
           /* do the i/o */
           status = spi_sync(spi, &message);
           if (status == 0)
                  memcpy(rxbuf, x[1].rx_buf, n_rx);
     
           if (x[0].tx_buf == buf)
                  mutex_unlock(&lock);
           else
                  kfree(local_buf);
     
           return status;
    }
    
    

     

     

    SPI sync

    读写都会调用到spi_sync

    int spi_sync(struct spi_device *spi, struct spi_message *message)
    {
           return __spi_sync(spi, message, 0);
    }
    
    


     

    接着调用了__spi_sync

     

    static int __spi_sync(struct spi_device *spi, struct spi_message *message,
                        int bus_locked)
    {
           DECLARE_COMPLETION_ONSTACK(done);
           int status;
           struct spi_master *master = spi->master;
     
           message->complete = spi_complete;
           message->context = &done;
     
           if (!bus_locked)
                  mutex_lock(&master->bus_lock_mutex);
            status = spi_async_locked(spi, message);
     
           if (!bus_locked)
                  mutex_unlock(&master->bus_lock_mutex);
     
           if (status == 0) {
                  wait_for_completion(&done);
                  status = message->status;
           }
           message->context = NULL;
           return status;
    }
    
    


     

     

    然后就是spi_async

    int spi_async(struct spi_device *spi, struct spi_message *message)
    {
           struct spi_master *master = spi->master;
           int ret;
           unsigned long flags;
     
           spin_lock_irqsave(&master->bus_lock_spinlock, flags);
     
           if (master->bus_lock_flag)
                  ret = -EBUSY;
           else
                  ret = __spi_async(spi, message);
     
           spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
     
           return ret;
    }
    
    


     

    最后调用__spi_async

    static int __spi_async(struct spi_device *spi, struct spi_message *message)
    {
           struct spi_master *master = spi->master;
     
           /* Half-duplex links include original MicroWire, and ones with
            * only one data pin like SPI_3WIRE (switches direction) or where
            * either MOSI or MISO is missing.  They can also be caused by
            * software limitations.
            */
           if ((master->flags & SPI_MASTER_HALF_DUPLEX)
                         || (spi->mode & SPI_3WIRE)) {
                  struct spi_transfer *xfer;
                  unsigned flags = master->flags;
     
                  list_for_each_entry(xfer, &message->transfers, transfer_list) {
                         if (xfer->rx_buf && xfer->tx_buf)
                                return -EINVAL;
                         if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
                                return -EINVAL;
                         if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
                                return -EINVAL;
                  }
           }
    
           message->spi = spi;
           message->status = -EINPROGRESS;
           return master->transfer(spi, message);
    }
    
    


     

    返回了master->transfer(spi, message);那么就是控制器里去工作了。

     

    我用的是gpio模拟的spi,所以那用gpio模拟的那个控制器去看控制器的处理了。

    先还是看一下probe函数

     

    static int __init spi_gpio_probe(struct platform_device *pdev)
    
    {
    
           int                        status;
    
           struct spi_master           *master;
    
           struct spi_gpio                     *spi_gpio;
    
           struct spi_gpio_platform_data       *pdata;
    
           u16 master_flags = 0;
    
     
    
           pdata = pdev->dev.platform_data;
    
    #ifdef GENERIC_BITBANG
    
           if (!pdata || !pdata->num_chipselect)
    
                  return -ENODEV;
    
    #endif
    
     
    
           status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
    
           if (status < 0)
    
                  return status;
    
     
    
           master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);
    
           if (!master) {
    
                  status = -ENOMEM;
    
                  goto gpio_free;
    
           }
    
           spi_gpio = spi_master_get_devdata(master);
    
           platform_set_drvdata(pdev, spi_gpio);
    
     
    
           spi_gpio->pdev = pdev;
    
           if (pdata)
    
                  spi_gpio->pdata = *pdata;
    
     
    
           master->flags = master_flags;
    
           master->bus_num = pdev->id;
    
           master->num_chipselect = SPI_N_CHIPSEL;
    
           master->setup = spi_gpio_setup;
    
           master->cleanup = spi_gpio_cleanup;
    
     
    
           spi_gpio->bitbang.master = spi_master_get(master);
    
           spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
    
     
    
           if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;
    
           } else {
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;
    
                  spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;
    
           }
    
           spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;
    
           spi_gpio->bitbang.flags = SPI_CS_HIGH;
    
     
    
           status = spi_bitbang_start(&spi_gpio->bitbang);
    
           if (status < 0) {
    
                  spi_master_put(spi_gpio->bitbang.master);
    
    gpio_free:
    
                  if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
    
                         gpio_free(SPI_MISO_GPIO);
    
                  if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
    
                         gpio_free(SPI_MOSI_GPIO);
    
                  gpio_free(SPI_SCK_GPIO);
    
                  spi_master_put(master);
    
           }
    
     
    
           return status;
    
    }
    
    


     

    主要看下下面三个函数

    spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
    
    spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;
    
    status = spi_bitbang_start(&spi_gpio->bitbang); 
    
    


     

    spi_gpio_txrx_word_mode0;就是最后调用到的先放一边,spi_bitbang_start,看一下这个函数

     

    int spi_bitbang_start(struct spi_bitbang *bitbang)
    
    {
    
           int   status;
    
     
    
           if (!bitbang->master || !bitbang->chipselect)
    
                  return -EINVAL;
    
     
    
           INIT_WORK(&bitbang->work, bitbang_work);
    
           spin_lock_init(&bitbang->lock);
    
           INIT_LIST_HEAD(&bitbang->queue);
    
     
    
           if (!bitbang->master->mode_bits)
    
                  bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
    
     
    
           if (!bitbang->master->transfer)
    
                  bitbang->master->transfer = spi_bitbang_transfer;
    
           if (!bitbang->txrx_bufs) {
    
                  bitbang->use_dma = 0;
    
                  bitbang->txrx_bufs = spi_bitbang_bufs;
    
                  if (!bitbang->master->setup) {
    
                         if (!bitbang->setup_transfer)
    
                                bitbang->setup_transfer =
    
                                        spi_bitbang_setup_transfer;
    
                         bitbang->master->setup = spi_bitbang_setup;
    
                         bitbang->master->cleanup = spi_bitbang_cleanup;
    
                  }
    
           } else if (!bitbang->master->setup)
    
                  return -EINVAL;
    
           if (bitbang->master->transfer == spi_bitbang_transfer &&
    
                         !bitbang->setup_transfer)
    
                  return -EINVAL;
    
     
    
           /* this task is the only thing to touch the SPI bits */
    
           bitbang->busy = 0;
    
           bitbang->workqueue = create_singlethread_workqueue(
    
                         dev_name(bitbang->master->dev.parent));
    
           if (bitbang->workqueue == NULL) {
    
                  status = -EBUSY;
    
                  goto err1;
    
           }
    
     
    
           /* driver may get busy before register() returns, especially
    
            * if someone registered boardinfo for devices
    
            */
    
           status = spi_register_master(bitbang->master);
    
           if (status < 0)
    
                  goto err2;
    
     
    
           return status;
    
     
    
    err2:
    
           destroy_workqueue(bitbang->workqueue);
    
    err1:
    
           return status;
    
    }
    
    


     

    看到这个函数指针了吧:

    if (!bitbang->master->transfer)
    
                  bitbang->master->transfer = spi_bitbang_transfer;
    
    
    

    那么设备驱动调用的master->transfer(spi, message);就是调用到了spi_bitbang_transfer了,

     

    /**
    
     * spi_bitbang_transfer - default submit to transfer queue
    
     */
    
    int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
    
    {
    
           struct spi_bitbang   *bitbang;
    
           unsigned long        flags;
    
           int                 status = 0;
    
     
    
           m->actual_length = 0;
    
           m->status = -EINPROGRESS;
    
     
    
           bitbang = spi_master_get_devdata(spi->master);
    
     
    
           spin_lock_irqsave(&bitbang->lock, flags);
    
           if (!spi->max_speed_hz)
    
                  status = -ENETDOWN;
    
           else {
    
                  list_add_tail(&m->queue, &bitbang->queue);
    
                  queue_work(bitbang->workqueue, &bitbang->work);
    
           }
    
           spin_unlock_irqrestore(&bitbang->lock, flags);
    
     
    
           return status;
    
    }
    
    


    这里是把信息加到了bitbang->workqueue,然后在bitbang->work里处理

     

    再来看下bitbang->work做了什么

    static void bitbang_work(struct work_struct *work)
    
    {
    
           struct spi_bitbang   *bitbang =
    
                  container_of(work, struct spi_bitbang, work);
    
           unsigned long        flags;
    
     
    
           spin_lock_irqsave(&bitbang->lock, flags);
    
           bitbang->busy = 1;
    
           while (!list_empty(&bitbang->queue)) {
    
                  struct spi_message  *m;
    
                  struct spi_device     *spi;
    
                  unsigned         nsecs;
    
                  struct spi_transfer   *t = NULL;
    
                  unsigned         tmp;
    
                  unsigned         cs_change;
    
                  int                 status;
    
                  int                 do_setup = -1;
    
     
    
                  m = container_of(bitbang->queue.next, struct spi_message,
    
                                queue);
    
                  list_del_init(&m->queue);
    
                  spin_unlock_irqrestore(&bitbang->lock, flags);
    
     
    
                  /* FIXME this is made-up ... the correct value is known to
    
                   * word-at-a-time bitbang code, and presumably chipselect()
    
                   * should enforce these requirements too?
    
                   */
    
                  nsecs = 100;
    
     
    
                  spi = m->spi;
    
                  tmp = 0;
    
                  cs_change = 1;
    
                  status = 0;
    
     
    
                  list_for_each_entry (t, &m->transfers, transfer_list) {
    
     
    
                         /* override speed or wordsize? */
    
                         if (t->speed_hz || t->bits_per_word)
    
                                do_setup = 1;
    
     
    
                         /* init (-1) or override (1) transfer params */
    
                         if (do_setup != 0) {
    
                                status = bitbang->setup_transfer(spi, t);
    
                                if (status < 0)
    
                                       break;
    
                                if (do_setup == -1)
    
                                       do_setup = 0;
    
                         }
    
     
    
                         /* set up default clock polarity, and activate chip;
    
                          * this implicitly updates clock and spi modes as
    
                          * previously recorded for this device via setup().
    
                          * (and also deselects any other chip that might be
    
                          * selected ...)
    
                          */
    
                         if (cs_change) {
    
                                bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
    
                                ndelay(nsecs);
    
                         }
    
                         cs_change = t->cs_change;
    
                         if (!t->tx_buf && !t->rx_buf && t->len) {
    
                                status = -EINVAL;
    
                                break;
    
                         }
    
     
    
                         /* transfer data.  the lower level code handles any
    
                          * new dma mappings it needs. our caller always gave
    
                          * us dma-safe buffers.
    
                          */
    
                         if (t->len) {
    
                                /* REVISIT dma API still needs a designated
    
                                 * DMA_ADDR_INVALID; ~0 might be better.
    
                                 */
    
                                if (!m->is_dma_mapped)
    
                                       t->rx_dma = t->tx_dma = 0;
    
                                status = bitbang->txrx_bufs(spi, t);
    
                         }
    
                         if (status > 0)
    
                                m->actual_length += status;
    
                         if (status != t->len) {
    
                                /* always report some kind of error */
    
                                if (status >= 0)
    
                                       status = -EREMOTEIO;
    
                                break;
    
                         }
    
                         status = 0;
    
     
    
                         /* protocol tweaks before next transfer */
    
                         if (t->delay_usecs)
    
                                udelay(t->delay_usecs);
    
     
    
                         if (!cs_change)
    
                                continue;
    
                         if (t->transfer_list.next == &m->transfers)
    
                                break;
    
     
    
                         /* sometimes a short mid-message deselect of the chip
    
                          * may be needed to terminate a mode or command
    
                          */
    
                         ndelay(nsecs);
    
                         bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
    
                         ndelay(nsecs);
    
                  }
    
     
    
                  m->status = status;
    
                  m->complete(m->context);
    
     
    
                  /* normally deactivate chipselect ... unless no error and
    
                   * cs_change has hinted that the next message will probably
    
                   * be for this chip too.
    
                   */
    
                  if (!(status == 0 && cs_change)) {
    
                         ndelay(nsecs);
    
                         bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
    
                         ndelay(nsecs);
    
                  }
    
     
    
                  spin_lock_irqsave(&bitbang->lock, flags);
    
           }
    
           bitbang->busy = 0;
    
           spin_unlock_irqrestore(&bitbang->lock, flags);
    
    }
    
    


     

    当队列非空的时候就一直去取队列的数据,然后会执行到

    status = bitbang->setup_transfer(spi, t);
    
    


    这个函数,因为在spi_bitbang_start

    if (!bitbang->txrx_bufs) {
    
                  bitbang->use_dma = 0;
    
                  bitbang->txrx_bufs = spi_bitbang_bufs;
    
                  if (!bitbang->master->setup) {
    
                         if (!bitbang->setup_transfer)
    
                                bitbang->setup_transfer =
    
                                        spi_bitbang_setup_transfer;
    
                         bitbang->master->setup = spi_bitbang_setup;
    
                         bitbang->master->cleanup = spi_bitbang_cleanup;
    
                  }
    
           }
    
    


    所以就调用了spi_bitbang_setup_transfer;

     

     

    int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
    
    {
    
           struct spi_bitbang_cs      *cs = spi->controller_state;
    
           u8                  bits_per_word;
    
           u32                hz;
    
     
    
           if (t) {
    
                  bits_per_word = t->bits_per_word;
    
                  hz = t->speed_hz;
    
           } else {
    
                  bits_per_word = 0;
    
                  hz = 0;
    
           }
    
     
    
           /* spi_transfer level calls that work per-word */
    
           if (!bits_per_word)
    
                  bits_per_word = spi->bits_per_word;
    
           if (bits_per_word <= 8)
    
                  cs->txrx_bufs = bitbang_txrx_8;
    
           else if (bits_per_word <= 16)
    
                  cs->txrx_bufs = bitbang_txrx_16;
    
           else if (bits_per_word <= 32)
    
                  cs->txrx_bufs = bitbang_txrx_32;
    
           else
    
                  return -EINVAL;
    
     
    
           /* nsecs = (clock period)/2 */
    
           if (!hz)
    
                  hz = spi->max_speed_hz;
    
           if (hz) {
    
                  cs->nsecs = (1000000000/2) / hz;
    
                  if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))
    
                         return -EINVAL;
    
           }
    
     
    
           return 0;
    
    }
    
    


     

    这里主要是根据bits_per_word选择传输的方式,分816,32三种模式,ads7843touchscreen是用bits_per_word默认没有,选择bitbang_txrx_8的。

     

    static unsigned bitbang_txrx_8(
    
           struct spi_device     *spi,
    
           u32                (*txrx_word)(struct spi_device *spi,
    
                                       unsigned nsecs,
    
                                       u32 word, u8 bits),
    
           unsigned         ns,
    
           struct spi_transfer   *t
    
    ) {
    
           unsigned         bits = t->bits_per_word ? : spi->bits_per_word;
    
           unsigned         count = t->len;
    
           const u8         *tx = t->tx_buf;
    
           u8                  *rx = t->rx_buf;
    
     
    
           while (likely(count > 0)) {
    
                  u8           word = 0;
    
     
    
                  if (tx)
    
                         word = *tx++;
    
                  word = txrx_word(spi, ns, word, bits);
    
                  if (rx)
    
                         *rx++ = word;
    
                  count -= 1;
    
           }
    
           return t->len - count;
    
    }
    
     
    
    


    这里word = txrx_word(spi, ns, word, bits);会调用到哪里呢?,首先看下这个函数的指针指向哪里。

    spi_bitbang_start中,bitbang->master->setup = spi_bitbang_setup;

    然后在spi_bitbang_setup 中有

    cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
    
    


    所以,这个最终还是调用到了spi_gpio.c文件中的spi_gpio_spec_txrx_word_mode0

    static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
    
                  unsigned nsecs, u32 word, u8 bits)
    
    {
    
           unsigned flags = spi->master->flags;
    
           return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
    
    }
    
    


    然后这个函数就调用了bitbang_txrx_be_cpha0,这个函数在spi-bitbang-txrx.h

     

    static inline u32
    
    bitbang_txrx_be_cpha0(struct spi_device *spi,
    
                  unsigned nsecs, unsigned cpol, unsigned flags,
    
                  u32 word, u8 bits)
    
    {
    
           /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
    
     
    
           /* clock starts at inactive polarity */
    
           for (word <<= (32 - bits); likely(bits); bits--) {
    
     
    
                  /* setup MSB (to slave) on trailing edge */
    
                  if ((flags & SPI_MASTER_NO_TX) == 0)
    
                         setmosi(spi, word & (1 << 31));
    
                  spidelay(nsecs);      /* T(setup) */
    
     
    
                  setsck(spi, !cpol);
    
                  spidelay(nsecs);
    
     
    
                  /* sample MSB (from slave) on leading edge */
    
                  word <<= 1;
    
                  if ((flags & SPI_MASTER_NO_RX) == 0)
    
                         word |= getmiso(spi);
    
                  setsck(spi, cpol);
    
           }
    
           return word;
    
    }
    
    


    这里就是gpio模拟的spi总线的协议过程了。这样,从最上面设备程序调用到控制器的整个数据流就结束了。

     

    注:这里有一个很恶心的东东,就是在bitbang_txrx_16bitbang_txrx_32中的

    const u8         *tx = t->tx_buf;
    
    u8                  *rx = t->rx_buf;
    
    


    这里是强制转换的,由于大小端的问题,可能导致数据相反,从而传输会出现问题的,如果是8bit的,那么就没有任何问题了。

    一段小插曲,也是用逻辑分析仪抓到的数据才发现的,如果没有这玩意儿,估计现在还纠结着。

    OK,至此,linuxSPI的数据传输就到这里了。

     

     

     

  • 相关阅读:
    jQuery -JQ方法大全
    Javascript模块化编程:模块的写法
    angular 路由的简单使用
    jQuery Validate验证框架
    网站出现403 Forbidden错误的原因和解决办法
    js下拉刷新
    bootstrap栅格系统的属性及使用
    AJAX 跨域请求
    用js实现分页效果
    用一个例子读懂 RequireJS
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300059.html
Copyright © 2020-2023  润新知