qnx的spi记录

https://www.cnblogs.com/schips/p/protocol_spi_about.html (主要)

https://www.zhihu.com/question/308406342/answer/2901148391

https://www.bbsmax.com/A/lk5aa4Pm51/ (有基础测试代码)

https://baijiahao.baidu.com/s?id=1746087964061209214&wfr=spider&for=pc

https://blog.csdn.net/qq_44810226/article/details/127991578

其中上图的通信流程如下:

  1. SPI主机首先先将SS或CS线拉低,以此来告知SPI从机通信开始。

2.主机通过发送SCLK时钟信号,来告知从机即将进行的读写操作。这里的SCLK时钟信号是由SPI的模式来决定是高电平还是低电平有效的,这点在稍后会进行介绍。

3.主机(Master)将要发送的数据写到发送数据缓存区(Memory),缓存区经过移位寄存器(0~7),串行移位寄存器通过MOSI信号线将字节一位一位地移出去传送给从机,同时MISO接口接收到的数据经过移位寄存器一位一位地移到接收缓存区。

4.从机(Slave)也将自己的串行移位寄存器(0~7)中的内容通过MISO信号线返回给主机。同时通过MOSI信号线接收主机发送的数据,这样,两个移位寄存器中的内容就被交换。

最初的疑问:

1、必须由master先发送才能读取slave端数据吗?

答:应该是,暂时理解的是由主机发送时钟信号来通知采样和发送

2、spi一侧的收发只有一个缓冲区吗?

答:理解的应该是,因为本质上是master的一个buffer与slave的buffer的一个数据交互

3、master时候发送,什么时候接收?

答:根据极性和相位决定,但是在同一个上升沿和下降沿,一定会一个负责读取(采集),一个负责发送

QNX的spi接口理解:

QNX/qnx_ap/AMSS/platform/qal/clients/spi_client/src/spi_client.c

可以发现,在封装spi的读、取、交换三个接口的时候,一定会有发送的一个buffer存在,所以总会是先发送

在exchange接口,发送参数有3个(包括设备、长度和buf),接收参数只有1个buf

在spi_write_ex接口,发送参数3个,接收参数为0,应该代表不在乎接收的数据

spi_read_ex接口,发送参数为2个(设备和buf),接收参数为1个(buf)

static int spi_xchange_ex(int fd, uint32_t device, void *wbuf, void *rbuf, int len)
{
    int32_t retval=0;
    iov_t wiov[4];
    iov_t riov[1];

    if(fd < 0) {
        errno = EINVAL;
        return -1;
    }

    SETIOV(wiov+0, &device, sizeof(device));
    SETIOV(wiov+1, &len, sizeof(len));
    SETIOV(wiov+2, wbuf, len);
    SETIOV(riov+0, rbuf, len);

    if (devctlv(fd, DCMD_SPI_XCHANGE, 3, 1, wiov, riov, &retval)) {
        LOGE("devctlv failed");
        errno = EINVAL;
        goto err;
    }

    return retval;
err:
    return -1;
}

static int spi_write_ex(int fd, uint32_t device, void *buf, int len)
{
    int32_t retval=0;
    iov_t wiov[4];

    if(fd < 0) {
        errno = EINVAL;
        return -1;
    }

    SETIOV(wiov+0, &device, sizeof(device));
    SETIOV(wiov+1, &len, sizeof(len));
    SETIOV(wiov+2, buf, len);

    if (devctlv(fd, DCMD_SPI_WRITE, 3, 0, wiov, NULL, &retval)) {
        LOGE("devctlv failed");
        errno = EINVAL;
        goto err;
    }
    if (-1 == retval) {
        LOGE("spi write failed, len:%d ret:0x%x", len, retval);
        errno = EIO;
        goto err;
    } else if (-1 > retval) {
        errno = -retval;
        goto err;
    }

    return len;
err:
    return -1;
}

int spi_read_ex(int fd, uint32_t device, void *buf, int len)
{
    int32_t retval=0;
    iov_t wiov[3];
    iov_t riov[1];

    if(fd < 0) {
        errno = EINVAL;
        return -1;
    }

    SETIOV(wiov+0, &device, sizeof(device));
    SETIOV(wiov+1, &len, sizeof(len));
    SETIOV(riov+0, buf, len);

    if (devctlv(fd, DCMD_SPI_READ, 2, 1, wiov, riov, &retval)) {
        LOGE("devctlv failed");
        errno = EINVAL;
        goto err;
    }
    if (-1 == retval) {
        LOGE("spi read failed, len:%d ret:0x%x", len, retval);
        errno = EIO;
        goto err;
    } else if (-1 > retval) {
        errno = -retval;
        goto err;
    }

    return retval;
err:
    return -1;
}

spi更底层的接口封装:

QNX/qnx_ap/AMSS/platform/resources/spi_drv/spi_drv.c

static int io_devctl(resmgr_context_t *ctp, io_devctl_t *msg, IOFUNC_OCB_T *ocbp)
{
       case DCMD_SPI_READ:
       {
          char *data = (char*)_DEVCTL_DATA(msg->i);
          uint32_t device = *(uint32_t*)data;
          data += sizeof(device);
          int len = *(int*)data;
          data += sizeof(len);
    
          /* ensure that we don't transfer junk bytes for padded TX */
          memset(ocb->wbuf.virtualAddr, 0, len);
          memset(&msg->o, 0, sizeof(msg->o));
          msg->o.ret_val = start_hwd_transfer(ocb, device, &ocb->wbuf, len, &ocb->rbuf, len);
       }

        case DCMD_SPI_WRITE:
        {
          char *data = (char*)_DEVCTL_DATA(msg->i);
          uint32_t device = *(uint32_t*)data;
          data += sizeof(device);
          int len = *(int*)data;
          data += sizeof(len);
          void *buf = (void*)data;
        
          msg->o.ret_val = start_hwd_transfer(ocb, device, &ocb->wbuf, len, &ocb->rbuf, len);
        }
        break;

           case DCMD_SPI_XCHANGE:
           {
              char *data = (char*)_DEVCTL_DATA(msg->i);
              uint32_t device = *(uint32_t*)data;
              data += sizeof(device);
              int len = *(int*)data;
              data += sizeof(len);
              void *wbuf = (void*)data;
        
              memset(&msg->o, 0, sizeof(msg->o));
              msg->o.ret_val = start_hwd_transfer(ocb, device, &ocb->wbuf, len, &ocb->rbuf, len);
           }
           break;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值