FT93x D2XX学习笔记 - 6. USB转SPI Master

72 篇文章 39 订阅

FT93x支持7个USB interface,interface 1,2,3,4作为UART使用,可以用interface  5作为USB2SPI Master的interface,不过这里想试试VCP驱动,所以需要用到interface 1, 2, 3, 4,考虑只有FT930支持4个UART,选择1,2作为UART Interface,3选做SPI Master,4作为GPIO和配置控制,5选做I2C Master, 6选做SPI Slaver,7选做I2C Slaver,

FT93x支持4路SPI Master(可以支持SPI、DSPI、QSPI)。这里先只考虑SPI的情况,其中SCK、MISO、MOSI共用,4个CS脚分别控制,这里只考虑SPI0的情况。

1. 初始化IO

    #define GPIO_SPIM_CLK    34
    #define GPIO_SPIM_MISO    35
    #define GPIO_SPIM_MOSI    36

    #define GPIO_SPIM_SS0    30
    #define GPIO_SPIM_SS1    31
    #define GPIO_SPIM_SS2    32
    #define GPIO_SPIM_SS3    33

    #define pad_spim_ss0     pad30_spim_ss0

    //SPI IO initial
    gpio_function(GPIO_SPIM_CLK, pad_spim_sck);
    gpio_function(GPIO_SPIM_MOSI, pad_spim_mosi);
    gpio_function(GPIO_SPIM_MISO, pad_spim_miso);

    gpio_function(GPIO_SPIM_SS0, pad_spim_ss0);
    gpio_function(GPIO_SPIM_SS1, pad_spim_ss1);
    gpio_function(GPIO_SPIM_SS2, pad_spim_ss2);
    gpio_function(GPIO_SPIM_SS3, pad_spim_ss3);

    gpio_dir(GPIO_SPIM_CLK, pad_dir_output);
    gpio_dir(GPIO_SPIM_MOSI, pad_dir_output);
    gpio_dir(GPIO_SPIM_MISO, pad_dir_input);
    gpio_dir(GPIO_SPIM_SS0, pad_dir_output);

2. 初始化SPI

    /* Enable the SPI Master device... */
    sys_enable(sys_device_spi_master);

    /* Init/configure SPI master with fifo enabled and depth of 64 bytes */
    spi_init(SPIM, spi_dir_master, spi_mode_0, 8); //FREQ = 100M / 8, Value: 4/8/16/.../256
    spi_option(SPIM,spi_option_fifo_size,64); //FIFO size: 16(default) or 64
    spi_option(SPIM,spi_option_fifo,1);    //Enable FIFO
    spi_option(SPIM,spi_option_fifo_receive_trigger,1);

3. 主循环中SPIM处理函数,当接收到USB数据时,把数据写入SPI,并从SPI读回相应长度的数据,然后把读到的数据再回传给USB。

void usb2spimHandle(uint8_t idx)
{
    int32_t count = 0;
    uint8_t bufIn[USB_BUF_MAX] = {0};
    uint8_t bufOut[USB_BUF_MAX] = {0};
    count = D2XX_Read(USB_INTERFACE_SPIM, bufOut, USB_BUF_MAX);
    if(count > 0)
    {
        spi_xchangen(SPIM, bufIn, bufOut, count);

        D2XX_Write(USB_INTERFACE_SPIM, bufIn, count);
    }
}

3. 为了通信速度,选择Interface 4作为配置通道(理论上也可以只使用Interface 3完成SPI通信,只需要自定义一套协议,这样不需要打开2路),设置选择哪个SPI作为通信,这里自定义一套协议。

void usb2cfgLoop(void)
{
    int32_t count = 0;
    uint8_t buf[USB_BUF_MAX] = {0};
    count = D2XX_Read(USB_INTERFACE_CFG, buf, USB_BUF_MAX);

    if(count > 0)
    {
        //dbg("cfg cmd:%d\r\n", buf[0]);
        switch(buf[0]) //cfg command
        {
            case USB2CFG_CMD_CFG_UART:
                break;
            case USB2CFG_CMD_CFG_SPI: //Config SPI
                break;
            case USB2CFG_CMD_SEL_SPI: //Select SPI
                if(buf[2] == 0)
                    spi_open(SPIM, buf[1]);
                else
                    spi_close(SPIM, buf[1]);
                break;

            case USB2CFG_GPIO_OUTPUT:
                gpio_write(buf[1], buf[2]);
                break;
            case USB2CFG_NULL:
            default:
                break;
        }
        D2XX_Write(USB_INTERFACE_CFG, buf, count);
    }

}

4. 测试平台采用C# +VCP驱动(非D2XX驱动) + VM816C,即PC端看起来是一个USB转UART设备,但是FT930实现的SPI功能,C#编程采用的是普通串口的API。C#端开2个serialport,分别为serialPort和serialPortCfg,先实现GPIO复位BT816,GPIO15复位BT816。

        public override void reset()
        {
            byte[] buf = new byte[3];
            buf[0] = (byte)eCfgCmd.USB2CFG_GPIO_OUTPUT;
            buf[1] = 15;
            buf[2] = 0;
            serialPortCfg.Write(buf, 0, 3);
            while (serialPortCfg.BytesToRead < 3) ;
            serialPortCfg.Read(buf, 0, 3);
            Thread.Sleep(10);
            buf[0] = (byte)eCfgCmd.USB2CFG_GPIO_OUTPUT;
            buf[1] = 15;
            buf[2] = 1;
            serialPortCfg.Write(buf, 0, 3);
            while (serialPortCfg.BytesToRead < 3) ;
            serialPortCfg.Read(buf, 0, 3);
            Thread.Sleep(10);
        }

6. 实现SPIM的CS选择

        public override void ft8xxCSEn()
        {
            byte[] buf = new byte[3];
            buf[0] = (byte)eCfgCmd.USB2CFG_CMD_SEL_SPI;
            buf[1] = 0;
            buf[2] = 0;
            serialPortCfg.Write(buf, 0, 3);
            while (serialPortCfg.BytesToRead < 3) ;
            serialPortCfg.Read(buf, 0, 3);
        }

        public override void ft8xxCSDis()
        {
            byte[] buf = new byte[3];
            buf[0] = (byte)eCfgCmd.USB2CFG_CMD_SEL_SPI;
            buf[1] = 0;
            buf[2] = 1;
            serialPortCfg.Write(buf, 0, 3);
            while (serialPortCfg.BytesToRead < 3) ;
            serialPortCfg.Read(buf, 0, 3);
        }

7. 实现SPI的通信API函数,因为串口通信不能一次把所有数据发送完(大笔数据时),所以API函数中采用分批写入数据,因为USB通信采用相同的全双工的方式,写入多少数据就会得到多少数据,所以发送完后等待接收数据(实际应该要加Timeout处理)

        private int comTranserSize = 2048 * 1;

        public override void spiTransferBytes(byte[] wrBuf, byte[] rdBuf, UInt32 len)
        {
            int offset = 0;
            int length = (int)len;
            while(length > 0)
            {
                int count = length > comTranserSize ? comTranserSize : (int)length;
                //Console.WriteLine("len:" + length + " offset:" + offset + " cnt:" + count);
                serialPort.Write(wrBuf, offset, count);
                
                while (serialPort.BytesToRead < count)
                {
                    Thread.Sleep(1);
                }
                serialPort.Read(rdBuf, offset, count);
                offset += count;
                length -= count;
            }
        }

8. 通信速度的研究

每次通信的字节数(comTranserSize )会影响到通信速度,目前发现配置为2048时是最快的,可以达到约1MByte/s,如果配置成4096通信就会失败。

注意:该速度是在COM通信中延时计时器默认是16ms。

而4096可能是和USB传输大小设置有关,最大只能到4096。

如果修改延时计时器为1ms,通信也会失败,应该是MCU端处理不过来了,改成8ms测试通信速度也并不会变快。

在Loop测试中使用D2XX验证数据可以达到7MByte/s,这里使用VCP却只能到1MByte/s,感觉如果使用D2XX的话速度应该可以做到更快(待验证)。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值