spi整体框架如下:
其中我主要讲到的是如下红框的内容
1.先说一下这个bitbang_work的由来
在spi设备驱动(主要是设备)的初始化中/drivers/spi/fsl_espi.c
fsl_espi_probe中调用了spi_bitbang_start,其中注册了队列处理bitbang_work
INIT_WORK(&bitbang->work, bitbang_work);
这就是它的由来了。
2.bitbang_work就实现了上图右侧部分的取message,这个message就是包含该主从设备配置和真实要发送的信息
简单看一下其中的几段代码
1)从message中获取配置数据然后配置到master
跟进去后会发现是设置master的位宽、模式、时钟频率、片选等
/* init (-1) or override (1) transfer params */
if (do_setup != 0) {
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
status = setup_transfer(spi, t);
if (status < 0)
break;
}
/* 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);
}
3)数据发送
这个就是数据收发的关键
/* 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);
}
3.数据收发具体实现
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct fsl_espi *fsl_espi;
u32 word, len, bits_per_word;
fsl_espi = spi_master_get_devdata(spi->master);
fsl_espi->tx = t->tx_buf;
fsl_espi->rx = t->rx_buf;
bits_per_word = spi->bits_per_word;
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
len = t->len;
fsl_espi->count = len;
/* every frame owns one byte */
out_be32(&fsl_espi->regs->command,
(spi->chip_select << 30) | (len - 1));
INIT_COMPLETION(fsl_espi->done);
/* enable rx ints */
out_be32(&fsl_espi->regs->mask, SPIM_NE);
/* transmit word */
word = fsl_espi->get_tx(fsl_espi);
out_be32(&fsl_espi->regs->transmit, word);
wait_for_completion(&fsl_espi->done);
return t->len;
}
①设置master的command寄存器,要发送的字符长度和从设备的片选
②初始化完成量
③使能收中断
④发送第一个字
⑤完成量等待
这个部分不难理解,重点就是在之后数据的收发
来看一下中断处理函数
irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
{
struct fsl_espi *fsl_espi = context_data;
u32 event, rx_data, word;
int ret;
/* Get interrupt events(tx/rx) */
event = in_be32(&fsl_espi->regs->event);
/* We need handle RX first */
if (event & SPIE_NE) {
/* spin until RX is done */
void *event_ptr = &fsl_espi->regs->event;
int limit = min(4, fsl_espi->count);
ret = spin_event_timeout(
SPIE_RXCNT(event = in_be32(event_ptr)) >= limit,
500, 0);
if (!ret)
return IRQ_NONE;
rx_data = in_be32(&fsl_espi->regs->receive);
if (fsl_espi->rx)
fsl_espi->get_rx(rx_data, fsl_espi);
} else {
/* Clear the events */
out_be32(&fsl_espi->regs->event, event);
return IRQ_HANDLED;
}
fsl_espi->count -= 4;
if (fsl_espi->count > 0) {
if ((event & SPIE_NF) == 0) {
/* spin until TX is done */
ret = spin_event_timeout((event =
in_be32(&fsl_espi->regs->event)) & SPIE_NF,
500, 0);
if (!ret)
return IRQ_NONE;
}
word = fsl_espi->get_tx(fsl_espi);
out_be32(&fsl_espi->regs->transmit, word);
} else {
fsl_espi->count = 0;
/* disable rx ints */
out_be32(&fsl_espi->regs->mask, 0);
complete(&fsl_espi->done);
}
/* Clear the events */
out_be32(&fsl_espi->regs->event, event);
return IRQ_HANDLED;
}
⑥读取中断,判断中断类型
⑦读取数据,保存
⑧判断剩余长度,若没发送完继续发送一个字
⑨已发送完,关中断,返回完成量
⑩清中断,返回
关于这个中断处理容易进入一个误区,就是:
先发送一个字后,从设备回应给主设备时产生的中断
那么按照这个思路分析,如果从设备收到数据后故意不给回应(fpga可以模拟spi时序),那程序会一直等在⑤的地方
导致spi异常死锁...
这种情况是一定不能出现的
正确的机制是:当spi片选中某一从设备,发送第一个字时,片选、时钟、MOSI、MISO会同时有效
通俗一点就是,当我们在发数据的时候spi同时在接收数据(全双工)
即使从设备没有发数据,spi的外围电路会将MISO拉高或拉低,同样相当于数据进来了。
那么就很明了了,过程如下:
Ⅰ、使能收中断,发送第一个字,同时收到来的数据
Ⅱ、收中断到来,收取数据
Ⅲ、继续发送剩余数据
Ⅱ、Ⅲ循环
Ⅳ、数据发送完成,关中断,完成量返回