210 SPI程序

对于spi的只是请先阅读我的上一篇文章
http://blog.csdn.net/zlw1005/article/details/43731067

先上一个210 SPI工作流程图
这里写图片描述

首先上spi 初始化寄存器函数

static void spireg_init(void)
{
    u32 val=0;
    if(spi_message.mode&SPI_CPOL_MASK)
    val |= ~SPI_CPOL;
    else
    val &=SPI_CPOL;

    if(spi_message.mode&SPI_CPHA_MASK)
        val |= ~SPI_CPHA;
    else
        val &=SPI_CPHA;
    val |= SPI_MASTER;
    writel(val,regs+S3C64XX_SPI_CH_CFG);    //设置spi 控制器为主机

    val = readl(regs+S3C64XX_SPI_CLK_CFG);
    val |= ((clk_get_rate(srcclk) / spi_message.speed/ 2 - 1)/*datasheet有计算公式*/
            & SPI_SPEED_MASK)|CLK_ENCLK|SPI_PCLK;   //设置spi速率以及时钟源选择
    DBG("val %d %d %d ",val,(int)(clk_get_rate(srcclk) / spi_message.speed/ 2 - 1),(int)clk_get_rate(srcclk) );     
    writel(val,regs+S3C64XX_SPI_CLK_CFG);
    val = readl(regs+S3C64XX_SPI_MODE_CFG);

    val |= CH_WIDTH_BYTE|BUS_WIDTH_BYTE;   //设置传送数据宽度byte

    writel(val,regs+S3C64XX_SPI_MODE_CFG);
    writel(0, regs+S3C64XX_SPI_INT_EN);//不使用中断

    val=readl(regs+S3C64XX_SPI_SLAVE_SEL);
    writel(1,regs+S3C64XX_SPI_SLAVE_SEL);//关闭spi使能

    val=readl(regs+S3C64XX_SPI_PACKET_CNT);
    val |=0xffff;
    writel(val,regs+S3C64XX_SPI_PACKET_CNT);//spi数据数目 bytes

}
  设置控制器主从数据相位
```![](http://img.blog.csdn.net/20150304160703061)






<div class="se-preview-section-delimiter"></div>

if(spi_message.mode&SPI_CPOL_MASK)
val |= ~SPI_CPOL;
else
val &=SPI_CPOL;

if(spi_message.mode&SPI_CPHA_MASK)
    val |= ~SPI_CPHA;
else
    val &=SPI_CPHA;
val |= SPI_MASTER;
writel(val,regs+S3C64XX_SPI_CH_CFG);    //设置spi 控制器为主机


时钟源选择,传输速率设置
![这里写图片描述](https://img-blog.csdn.net/20150304161028150)





<div class="se-preview-section-delimiter"></div>

val |= ((clk_get_rate(srcclk) / spi_message.speed/ 2 - 1)/datasheet有计算公式/
& SPI_SPEED_MASK)|CLK_ENCLK|SPI_PCLK; //设置spi速率以及时钟源选择
DBG(“val %d %d %d “,val,(int)(clk_get_rate(srcclk) / spi_message.speed/ 2 - 1),(int)clk_get_rate(srcclk) );
writel(val,regs+S3C64XX_SPI_CLK_CFG);


设置位宽
![这里写图片描述](https://img-blog.csdn.net/20150304161339620)





<div class="se-preview-section-delimiter"></div>

val |= CH_WIDTH_BYTE|BUS_WIDTH_BYTE; //设置传送数据宽度byte writel(val,regs+S3C64XX_SPI_MODE_CFG);

读写同步函数





<div class="se-preview-section-delimiter"></div>

static void transer_write_read(void)
{
int i=0,j=0,ms;
u32 val,loops;

 writel(((spi_message.length* 8 / 8) & 0xffff)
                | SPI_PACKET_CNT_EN,
                regs + S3C64XX_SPI_PACKET_CNT);
    for(i = 0;i<spi_message.length;i++)
    DBG("write %d\n",spi_message.send[i]);

    i=0;
    while(i < spi_message.length)
        writeb(spi_message.send[i++], regs + S3C64XX_SPI_TX_DATA);
 val = readl(regs + S3C64XX_SPI_CH_CFG);
 val =(RX_CH_ON | TX_CH_ON);
 writel(val, regs + S3C64XX_SPI_CH_CFG);

    writel(0, regs + S3C64XX_SPI_SLAVE_SEL);
    gpio_set_value(S5PV210_GPB(5),1);


    ms =spi_message.length* 8 * 1000 / spi_message.speed+20;
    loops = msecs_to_loops(ms);

    do{
        val = readl(regs+S3C64XX_SPI_STATUS);
     }while(loops-- && RX_FIFO_LVL(val)<spi_message.length);//wait for rx fifo receive spi_message.length

     spi_readregs(regs);
     while(j<spi_message.length)
     {
       spi_message.receive[j++] = readb(regs + S3C64XX_SPI_RX_DATA);
       DBG(" %x\n ",spi_message.receive[j-1]);
     }
      DBG("read after\n");
      spi_readregs(regs);
     writel(1, regs + S3C64XX_SPI_SLAVE_SEL);
     gpio_set_value(S5PV210_GPB(5),0);
     spi_flush_fifo();

}

由于传输数据很频繁,这里采用mmap方式实现内核和用户态数据交互,提高效率




<div class="se-preview-section-delimiter"></div>

static int myspi_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
int spi_size = vma->vm_end - vma->vm_start;
vma->vm_flags |= VM_IO;
vma->vm_flags |= VM_RESERVED;
if(map_index++)//第一次映射send
{
ret = remap_pfn_range(vma, vma->vm_start,
virt_to_phys(spi_message.send)>> PAGE_SHIFT,
spi_size, vma->vm_page_prot);
}
else
{
ret = remap_pfn_range(vma, vma->vm_start,
virt_to_phys(spi_message.receive)>> PAGE_SHIFT,
spi_size, vma->vm_page_prot);
}
if (ret)
return -EAGAIN;
return 0;
}

注意这里要映射的kmalloc分配的spi_message.receive(逻辑地址在物理内存上是连续的和vmalloc有区别)内存必须是PAGE_SIZE*n才能保证映射以及后续操作成功

stm32全双工通信的实现,由于spi协议中规定从机和主机通信的成功与否依赖于主机的时钟,所以我们这里使用一个IO口向210发送个跳变,210监测到就发送一个异步信号给用户层,主机开始产生sck给让从机能够通信成功





<div class="se-preview-section-delimiter"></div>

static irqreturn_t myspi_slave_irq(int irq, void *dev_id)
{
kill_fasync (&myspi_async, SIGIO, POLL_IN);
return IRQ_HANDLED;
}
“`
程序下载链接
http://download.csdn.net/detail/zlw1005/8472605

注意本程序只是个粗糙的测试程序,很多地方需要完善,请注意stm32芯片类型
还有210spi驱动我这边测试的时钟过高(远没有达到高速率)有问题,可能是我这边的硬件问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值