打印

FX3 CyU3PSpiTransmitWords API详解 (新手入门手册)

[复制链接]
2911|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zengweitotty|  楼主 | 2015-12-29 09:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 zengweitotty 于 2015-12-29 09:36 编辑

新手入门的系列文档【原创】
本贴讲解了API的使用方法和源代码分析。
如下是API的声明部分
CyU3PReturnStatus_t

CyU3PSpiTransmitWords (    //8162432 字节方式传输
                       uint8_t *data,    //传输数据的头指针
                       uint32_t byteCount)      //传输数据的数据量
1. 参数检查:
如果SPI 没有调用API CyU3PSpiSetConfig对SPI 进行初始化配置,返回CY_U3P_ERROR_NOT_CONFIGURED
如果byteCount0,返回CY_U3P_SUCCESS,不进行数据传输。
如果CyU3PSpiGetLock 不成功,返回相应的error code。源代码如下:

/* Get the lock for the SPI beforeany operation */
static CyU3PReturnStatus_t
CyU3PSpiGetLock (
                 void)
{
   uint32_t waitOption = 0;

   if (!glIsSpiActive)
   {
       return CY_U3P_ERROR_NOT_CONFIGURED;
   }
   if (CyU3PThreadIdentify() != NULL)
   {
       waitOption = CY_U3P_SPI_DEFAULT_LOCK_TIMEOUT;
   }

   if (CyU3PMutexGet(&glSpiLock, waitOption) != CY_U3P_SUCCESS)
   {
       return CY_U3P_ERROR_MUTEX_FAILURE;
   }

   return CY_U3P_SUCCESS;
}

其中如果没有经过CyU3PSpiInit 初始化,将会返回CY_U3P_ERROR_NOT_CONFIGURED
如果在进程上下文里面使用,则waitoption=CYU3P_WAIT_FOREVER,如果实在中断上下文使用,waitoption=0;如果获取互斥量glSpiLock失败则返回CY_U3P_ERROR_MUTEX_FAILURE
CyU3PSpiInt_ThreadHandlerCyU3PSpiSetConfigCyU3PSpiSetSsnLineCyU3PSpiTransmitWordsCyU3PSpiReceiveWordsCyU3PSpiSetBlockXferCyU3PSpiDisableBlockXferCyU3PSpiWaitForBlockXfer操作时会竞争互斥量glSpiLock
2. SPI_CONFIG解析wordLen, wordLen 要大于等于4,小于等于320-3bit将会保留。
   如果SPI_CONFIGWL[5:0]的第三位不为0,则向上WL[3]+=1;
  如果参数byteCount 不是wordLen的整数倍,则会返回CY_U3P_ERROR_BAD_ARGUMENT错误
file:///C:\Users\weiz\AppData\Local\Temp\msohtmlclip1\01\clip_image002.png
3. 检查SPIblock是否已经以DMA mode运行(此APISPI registermode下使用),则会返回CY_U3P_ERROR_ALREADY_STARTED
4. 调用CyU3PSpiResetFifo API 复位Tx FIFO,通过写SPI_CONFIG寄存器的TX_CLEAR位来清除FIFO,同时检测SPI_STATUSTX_DONE位来确认FIFO是否已经为空。

SPI_CONFIG:
file:///C:\Users\weiz\AppData\Local\Temp\msohtmlclip1\01\clip_image004.jpg
SPI_STATUS:
file:///C:\Users\weiz\AppData\Local\Temp\msohtmlclip1\01\clip_image006.jpg
通过源代码如下:

/*
* Resets the FIFO.
* Leaves SPI block disabled at the end.
*/
static CyU3PReturnStatus_t
CyU3PSpiResetFifo (
                   CyBool_t isTx,
                   CyBool_t isRx
                   )
{
   uint32_t intrMask;
   uint32_t ctrlMask = 0;
   uint32_t temp;

   /*No lock is acquired or error checked as this is
   * an internal function. Locks need to be acquired
   * prior to this call. */

   /*Temporarily disable interrupts. */
   intrMask = SPI->lpp_spi_intr_mask;
   SPI->lpp_spi_intr_mask = 0;

   if (isTx)
   {
       ctrlMask = CY_U3P_LPP_SPI_TX_CLEAR;
   }
   if (isRx)
   {
       ctrlMask |= CY_U3P_LPP_SPI_RX_CLEAR;
   }

   /*Disable the SPI block and reset. */
   temp = ~(CY_U3P_LPP_SPI_RX_ENABLE | CY_U3P_LPP_SPI_TX_ENABLE |
       CY_U3P_LPP_SPI_DMA_MODE | CY_U3P_LPP_SPI_ENABLE);
   SPI->lpp_spi_config &= temp;
   while ((SPI->lpp_spi_config &CY_U3P_LPP_SPI_ENABLE) != 0);

   /*Clear the FIFOs and wait until they have been cleared. */
   SPI->lpp_spi_config |= ctrlMask;
   if (isTx)
   {
       while ((SPI->lpp_spi_status &CY_U3P_LPP_SPI_TX_DONE) == 0);
   }
   if (isRx)
   {
       while ((SPI->lpp_spi_status &CY_U3P_LPP_SPI_RX_DATA) != 0);
   }
   SPI->lpp_spi_config &= ~ctrlMask;

   /*Clear all interrupts and re-enable them. */
   SPI->lpp_spi_intr |= CY_U3P_LPP_SPI_TX_DONE;
   SPI->lpp_spi_intr_mask = intrMask;

   return CY_U3P_SUCCESS;
}

5. SPI_EGRESS_DATA寄存器开始传输SPI数据
       暂时关闭中断
  /*Disable interrupts. */
   intrMask = SPI->lpp_spi_intr_mask;
    SPI->lpp_spi_intr_mask = 0;
       使能SPI TX功能
   /*Enable the TX. */
   SPI->lpp_spi_config |=CY_U3P_LPP_SPI_TX_ENABLE;
       使能SPI 功能
   /*Re-enable SPI block. */
SPI->lpp_spi_config |= CY_U3P_LPP_SPI_ENABLE;
设置timeout参数,如果未使用CyU3PSpiSetTimeout API设置timeout参数的话,在CyU3PSpiInit API设置默认的timeout参数如下:

glSpiReadTimeout  =CY_U3P_SPI_TIMEOUT;     

// #defineCY_U3P_SPI_TIMEOUT (0xFFFFF) /* Default timeout for SPI data transfers. */
glSpiWriteTimeout = CY_U3P_SPI_TIMEOUT;

    timeout = glSpiWriteTimeout;

CyU3PSpiTransmitWords API详解.pdf

487.13 KB

原文的pdf版本(原创)

沙发
zengweitotty|  楼主 | 2015-12-29 09:19 | 只看该作者
6. 检测SPI_STATUSTX_SPACE bit来确定TX FIFO中是否有空间存储需要发送的数据。如果在timeout时间内一直未发送出去数据,将会返回CY_U3P_ERROR_TIMEOUT
file:///C:%5CUsers%5Cweiz%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image008.jpg
按照LSB的方式填充SPI_EGRESS_DATA寄存器。
       /*Copy data to be written into local variable.
        * The padding required is to nearestbyte.
        * Do fallthrough switch insteadof a loop. */
       temp = 0;
        switch (wordLen)
        {
        case 4:
            temp = (data[i + 3] << 24);
        case 3:
            temp |= (data[i + 2] << 16);
        case 2:
            temp |= (data[i + 1] << 8);
        case 1:
            temp |= data;
        default:
            break;
        }

       SPI->lpp_spi_egress_data = temp;
7. 通过检测SPI_INTR寄存器的TX_DONE来确定数据是否发送完成。之后清TX_DONE中断。直到byteCount 字节的数据发送完成。
file:///C:%5CUsers%5Cweiz%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image010.jpg
8. 发送完成处理
禁止TX
   /*Disable the TX. */
   SPI->lpp_spi_config&= ~CY_U3P_LPP_SPI_TX_ENABLE;
清除TX_DONE中断,根据进入此函数时的intrmark寄存器的值恢复SPI mark寄存器
   /*Clear all interrupts and restore interrupt mask. */
   SPI->lpp_spi_intr|= CY_U3P_LPP_SPI_TX_DONE;
    SPI->lpp_spi_intr_mask = intrMask;
等待SPI_STATUS寄存器的BUSY bit0,表示TX FIFO中的数据已经全部发送完成
   /*Wait until the SPI block is no longer busy and disable. */

while((SPI->lpp_spi_status & CY_U3P_LPP_SPI_BUSY) != 0);

file:///C:%5CUsers%5Cweiz%5CAppData%5CLocal%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_image012.jpg
禁止SPI使能
SPI->lpp_spi_config &= ~CY_U3P_LPP_SPI_ENABLE;
释放glSpiLock互斥量
   CyU3PSpiReleaseLock();

使用特权

评论回复
板凳
zengweitotty|  楼主 | 2015-12-29 09:20 | 只看该作者
图片看不了,如有兴趣,可以下载pdf看看。

使用特权

评论回复
地板
zengweitotty|  楼主 | 2015-12-29 09:32 | 只看该作者
关于SPI TX优化的做法:
1. 可以对发送作如下的优化:
   检测SPI_STATUS的TX_SPACE bit,是否能够继续想TX FIFO中填充数据。最后检测TX_DONE中断
  for (i = 0; i < byteCount; i += wordLen)
    {
        /* Copy data to be written into local variable.
        * The padding required is to nearest byte.
        * Do fallthrough switch instead of a loop. */
        temp = 0;
        switch (wordLen)
        {
        case 4:
            temp = (data[i + 3] << 24);
        case 3:
            temp |= (data[i + 2] << 16);
        case 2:
            temp |= (data[i + 1] << 8);
        case 1:
            temp |= data;
        default:
            break;
        }
        /* Wait for the tx_space bit in status register */
        while (!(SPI->lpp_spi_status & CY_U3P_LPP_SPI_TX_SPACE))
        {
            if (timeout-- == 0)
            {
                status = CY_U3P_ERROR_TIMEOUT;
                break;
            }
        }
        if (status != CY_U3P_SUCCESS)
        {
            break;
        }
        SPI->lpp_spi_egress_data = temp;
}
数据发送分完成在检测SPI_INTR寄存器的TX_DONE bit,等待数据发送完成。
while (!(SPI->lpp_spi_intr & CY_U3P_LPP_SPI_TX_DONE))
    {
        if (timeout-- == 0)
        {
            status = CY_U3P_ERROR_TIMEOUT;
           break;
        }
   }
如下是改动后的源代码。
/*
* Transmits data word by word over
* the SPI interface.
*/
CyU3PReturnStatus_t
CyU3PSpiTransmitWords (
                       uint8_t *data,
                       uint32_t byteCount)
{
    uint8_t  wordLen;
    uint32_t intrMask, i;
    uint32_t temp, timeout;
    CyU3PReturnStatus_t status;
    if (!glIsSpiConfigured)
    {
        return CY_U3P_ERROR_NOT_CONFIGURED;
    }
    if (byteCount == 0)
    {
        return CY_U3P_SUCCESS;
    }
    if (data == NULL)
    {  
        return CY_U3P_ERROR_NULL_POINTER;
    }
    status = CyU3PSpiGetLock ();
    if (status != CY_U3P_SUCCESS)
    {
        return status;
    }
    /* Get the wordLen from the config register and convert it to byte length. */
    temp = SPI->lpp_spi_config;
    wordLen = ((temp & CY_U3P_LPP_SPI_WL_MASK) >> CY_U3P_LPP_SPI_WL_POS);
    if ((wordLen & 0x07) != 0)
    {
        wordLen = (wordLen >> 3) + 1;
    }
    else
    {
        wordLen = (wordLen >> 3);
    }
    if ((byteCount % wordLen) != 0)
    {
        status = CY_U3P_ERROR_BAD_ARGUMENT;
    }
    /* Check if the DMA mode is running. */
    if ((temp & (CY_U3P_LPP_SPI_DMA_MODE | CY_U3P_LPP_SPI_ENABLE))
        == (CY_U3P_LPP_SPI_DMA_MODE| CY_U3P_LPP_SPI_ENABLE))
    {
        status = CY_U3P_ERROR_ALREADY_STARTED;
    }
    if (status != CY_U3P_SUCCESS)
    {
        CyU3PSpiReleaseLock();
        return status;
    }
    CyU3PSpiResetFifo (CyTrue, CyFalse);
    /* Disable interrupts. */
    intrMask = SPI->lpp_spi_intr_mask;
    SPI->lpp_spi_intr_mask = 0;
    /* Enable the TX. */
    SPI->lpp_spi_config |= CY_U3P_LPP_SPI_TX_ENABLE;
    /* Re-enable SPI block. */
    SPI->lpp_spi_config |= CY_U3P_LPP_SPI_ENABLE;
    timeout = glSpiWriteTimeout;
    for (i = 0; i < byteCount; i += wordLen)
    {
        /* Copy data to be written into local variable.
        * The padding required is to nearest byte.
        * Do fallthrough switch instead of a loop. */
        temp = 0;
        switch (wordLen)
        {
        case 4:
            temp = (data[i + 3] << 24);
        case 3:
            temp |= (data[i + 2] << 16);
        case 2:
            temp |= (data[i + 1] << 8);
        case 1:
            temp |= data;
        default:
            break;
        }
        /* Wait for the tx_space bit in status register */
        while (!(SPI->lpp_spi_status & CY_U3P_LPP_SPI_TX_SPACE))
        {
            if (timeout-- == 0)
            {
                status = CY_U3P_ERROR_TIMEOUT;
                break;
            }
        }
        if (status != CY_U3P_SUCCESS)
        {
            break;
        }
        SPI->lpp_spi_egress_data = temp;
    }
    /* Wait for the TX_DONE interrupt */
    while (!(SPI->lpp_spi_intr & CY_U3P_LPP_SPI_TX_DONE))
    {
        if (timeout-- == 0)
        {
            status = CY_U3P_ERROR_TIMEOUT;
            break;
        }
    }
    /* Clear the TX_DONE interrupt. */
    SPI->lpp_spi_intr = CY_U3P_LPP_SPI_TX_DONE;
    /* Disable the TX. */
    SPI->lpp_spi_config &= ~CY_U3P_LPP_SPI_TX_ENABLE;
    /* Clear all interrupts and restore interrupt mask. */
    SPI->lpp_spi_intr |= CY_U3P_LPP_SPI_TX_DONE;
    SPI->lpp_spi_intr_mask = intrMask;
    /* Wait until the SPI block is no longer busy and disable. */
    while ((SPI->lpp_spi_status & CY_U3P_LPP_SPI_BUSY) != 0);
    SPI->lpp_spi_config &= ~CY_U3P_LPP_SPI_ENABLE;
    CyU3PSpiReleaseLock();
    return status;
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

61

帖子

19

粉丝