TI-RTOS-SPI深度解析

開發板:AM335X
編譯環境:css
qq:956465349
gdut15級本科

最近在移植rtos的spi-loopback的測試程序到am335x開發板上 順便把相關的操作函數源碼給分析了下
移植的是pdk_am335x_1_0_5\packages\ti\drv\spi\example\mcspiLoopbackApp的測試程序
spi的基礎知識可以看我覺得不錯的博客
http://blog.csdn.net/skyflying2012/article/details/11710801

一開始跑的肯定是main函數
一開始程序先跑Main程序

int main(void)
{
    /* Call board init functions */
    Board_initCfg boardCfg;
/* 我們的開發板是am335x 所以這裏會執行 */
#if defined(SOC_AM335x) || defined (SOC_AM437x)
    Task_Handle task;
    Error_Block eb;

    Error_init(&eb);
    /* 創建spi任務 main函數最終會執行spi_test函數 */
    task = Task_create(spi_test, NULL, &eb);
    /* 判斷Task_create是否成功 這裏是成功 */
        if (task == NULL) {
            System_printf("Task_create() failed!\n");
            BIOS_exit(0);
        }
#endif


    boardCfg = BOARD_INIT_PINMUX_CONFIG |
        BOARD_INIT_MODULE_CLOCK |
        BOARD_INIT_UART_STDIO;
    /* 根據boardCfg的參數判斷 執行相關的初始化函數 */
    Board_init(boardCfg);
    SPI_log("Board_init succeed. \n");


#if defined(SOC_AM572x) || defined (SOC_AM571x)
    MCSPI_Board_crossbarInit();
#endif

    /* Start BIOS */
    BIOS_start();
    return (0);
}

main函數主要就創建了一個任務 名字叫做spi_test也就是我們的主要程序處理
並且設置boardCfg的參數調用Board_init進行相關的初始化
進行

Board_STATUS Board_init(Board_initCfg cfg)
{
    /*定義int型變量ret來當函數返回值判斷  */
    Board_STATUS ret = BOARD_SOK;
    /* DDR3的PLL時鐘設置 */
    if (cfg & BOARD_INIT_PLL)
        ret = Board_PLLInit();
    if (ret != BOARD_SOK)
        return ret;
    /* 單板模塊時鐘的初始化 */
    if (cfg & BOARD_INIT_MODULE_CLOCK)
        ret = Board_moduleClockInit();
    if (ret != BOARD_SOK)
        return ret;
    /* DDR初始化 */
    if (cfg & BOARD_INIT_DDR)
        ret = Board_DDR3Init();
    if (ret != BOARD_SOK)
        return ret;
    /* ICSS管腳初始化 */
    if (cfg & BOARD_INIT_ICSS_PINMUX)
    {
        /* 設置flags 判斷是否是icssPinmux */
        icssPinMuxFlag = 1U;
        ret = Board_pinmuxConfig();
    }
    /* 管腳配置初始化 */
    else if (cfg & BOARD_INIT_PINMUX_CONFIG)
    {
        ret = Board_pinmuxConfig();
    }
    if (ret != BOARD_SOK)
        return ret;
    /* 標準輸入輸出串口初始化 */
    if (cfg & BOARD_INIT_UART_STDIO)
        ret = Board_uartStdioInit();
    if (ret != BOARD_SOK)
        return ret;

    return ret;
}

根據main函數中cfg參數色設置這裏只執行三個函數

Board_moduleClockInit();
Board_pinmuxConfig();
Board_uartStdioInit();

分別分析三個初始化函數
這裏主要關注的是串口和MCSPI時鐘的初始化

Board_STATUS Board_moduleClockInit()
{   
    int32_t status;

    /* UART時鐘 */
    /* UART0 UART1 UART3 UART4 */
    status = PRCMModuleEnable(CHIPDB_MOD_ID_UART, 0U, 0U);
    if(S_PASS == status)
    {
        status = PRCMModuleEnable(CHIPDB_MOD_ID_UART, 1U, 0U);
    }
    if(S_PASS == status)
    {
        status = PRCMModuleEnable(CHIPDB_MOD_ID_UART, 3U, 0U);
    }
    if(S_PASS == status)
    {
        status = PRCMModuleEnable(CHIPDB_MOD_ID_UART, 4U, 0U);
    }
    ....
    /* MCSPI */
    if(S_PASS == status)
    {/* SPI0 SPI1 */
        status = PRCMModuleEnable(CHIPDB_MOD_ID_MCSPI, 0U, 0U);
    }
    if(S_PASS == status)
    {
        status = PRCMModuleEnable(CHIPDB_MOD_ID_MCSPI, 1U, 0U);
    }
    ...
}

這裏其實就是根據前面的時鐘判斷來決定後面時鐘的配置
如果有一個模塊沒使能成功 那麼後面的都不能執行 所以這裏得判斷是否前面的沒有使能成功 而影響後面的mcspi的使能
大致的分析下有關的模塊使能 第一個是模塊ID每個模塊都有自己獨立的ID 第二個是某個模塊的號碼 比如UART1 UART0這些

#ifndef BUILDCFG_MOD_MCSPI
#define BUILDCFG_MOD_MCSPI
#endif /* BUILDCFG_MOD_MCSPI */

/** Peripheral Pin Configurations */
#ifndef BUILDCFG_MOD_UART
#define BUILDCFG_MOD_UART
#endif /* BUILDCFG_MOD_UART */


int32_t PRCMModuleEnable(chipdbModuleID_t moduleId, uint32_t instNum,
                                                    uint32_t isBlockingCall)
{
    int32_t status = S_PASS;
    switch(moduleId)
    {
    ...
    #if defined(BUILDCFG_MOD_UART)
        case CHIPDB_MOD_ID_UART:
        {
            switch(instNum)
            {
                case 0:
                    enableModule(SOC_CM_WKUP_REGS, CM_WKUP_UART0_CLKCTRL,
                        CM_WKUP_CLKSTCTRL,
                        CM_WKUP_CLKSTCTRL_CLKACTIVITY_UART0_GFCLK);
                    break;
               case 1:
                    enableModule(SOC_CM_PER_REGS, CM_PER_UART1_CLKCTRL,
                        CM_PER_L4LS_CLKSTCTRL,
                        CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_UART_GFCLK);
                    break;
               case 2:
                    enableModule(SOC_CM_PER_REGS, CM_PER_UART2_CLKCTRL,
                        CM_PER_L4LS_CLKSTCTRL,
                        CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_UART_GFCLK);
                    break;
               case 3:
                    enableModule(SOC_CM_PER_REGS, CM_PER_UART3_CLKCTRL,
                        CM_PER_L4LS_CLKSTCTRL,
                        CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_UART_GFCLK);
                    break;
               case 4:
                    enableModule(SOC_CM_PER_REGS, CM_PER_UART4_CLKCTRL,
                        CM_PER_L4LS_CLKSTCTRL,
                        CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_UART_GFCLK);
                    break;
                case 5:
                    enableModule(SOC_CM_PER_REGS, CM_PER_UART5_CLKCTRL,
                        CM_PER_L4LS_CLKSTCTRL,
                        CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_UART_GFCLK);
                    break;
            }
        }
        break;
    #endif /* if defined(BUILDCFG_MOD_UART) */

        ...

    #if defined(BUILDCFG_MOD_MCSPI)
            case CHIPDB_MOD_ID_MCSPI:
            {
                /* 兩次調用 所以SPI0和SPI1都能使能時鐘  */
                switch(instNum)
                {
                    case 0:
                        enableModule(SOC_CM_PER_REGS, CM_PER_SPI0_CLKCTRL,
                            CM_PER_L3_CLKSTCTRL, CM_PER_L3_CLKSTCTRL_CLKACTIVITY_L3_GCLK);
                        break;
                    case 1:
                        enableModule(SOC_CM_PER_REGS, CM_PER_SPI1_CLKCTRL,
                            CM_PER_L3_CLKSTCTRL, CM_PER_L3_CLKSTCTRL_CLKACTIVITY_L3_GCLK);
                        break;
                }
            }
            break;
    #endif /* if defined(BUILDCFG_MOD_MCSPI) */
    ...
     return status;
}

可以分析下enableModule參數是什麼使能模塊的時鐘的 其實只是往寄存器裏寫進入相關位 使能時鐘並且判斷

void enableModule(uint32_t domainOffset, uint32_t clkCtrlReg,
                uint32_t clkStCtrlReg, uint32_t clkActMask)
{
    /* Enable the module */
    /*  */
    HW_WR_REG32(domainOffset + clkCtrlReg, PRCM_MODULEMODE_ENABLE);
    /* Check for module enable status */
    while(PRCM_MODULEMODE_ENABLE !=
        (HW_RD_REG32(domainOffset + clkCtrlReg) & PRCM_MODULEMODE_MASK));
    /* Check clock activity - ungated */
    while(clkActMask != (HW_RD_REG32(domainOffset + clkStCtrlReg) & clkActMask));
    /* Check idle status value - should be in functional state */
    while((PRCM_MODULE_IDLEST_FUNC << PRCM_IDLE_ST_SHIFT) !=
        (HW_RD_REG32(domainOffset + clkCtrlReg) & PRCM_IDLE_ST_MASK));
}

如果沒設置成功的話就會死循環在這 所以要麼沒有運行enableModule要麼就執行
把SPI1的初始化時鐘代入可得

enableModule(0x44E00000, 0x50,
                            0xc, 0x00000010u);

void enableModule(uint32_t domainOffset, uint32_t clkCtrlReg,
                uint32_t clkStCtrlReg, uint32_t clkActMask)
{
    /* Enable the module */
    /*  */
    HW_WR_REG32(0x44E00000 + 0x50, 2);
    /* Check for module enable status */
    while(2 != (HW_RD_REG32(0x44E00000 + 0x50) & 3));
    /* Check clock activity - ungated */
    while(0x00000010u != (HW_RD_REG32(0x44E00000 + 0x50) & 0x00000010u));
    /* Check idle status value - should be in functional state */
    while((PRCM_MODULE_IDLEST_FUNC << PRCM_IDLE_ST_SHIFT) !=
        (HW_RD_REG32(domainOffset + clkCtrlReg) & PRCM_IDLE_ST_MASK));
}

查詢手冊0x44E00050寄存器 就是CM_PER_SPI1_CLKCTRL [1:0]設置爲0x2就是初始化了使能了模塊的時鐘

下面的是
Board_pinmuxConfig();這個函數對pinmux配置

Board_STATUS Board_pinmuxConfig (void)
{
    int32_t status;

    /* UART */
    status = PINMUXModuleConfig(CHIPDB_MOD_ID_UART, 0U, NULL);
    if(S_PASS == status)
    {
        status = PINMUXModuleConfig(CHIPDB_MOD_ID_UART, 1U, NULL);
    }
    if(S_PASS == status)
    {
        status = PINMUXModuleConfig(CHIPDB_MOD_ID_UART, 3U, NULL);
    }
    if(S_PASS == status)
    {
        status = PINMUXModuleConfig(CHIPDB_MOD_ID_UART, 4U, NULL);
    }
    ....
      /* MCSPI */
      /* */
    if(S_PASS == status)
    {
        status = PINMUXModuleConfig(CHIPDB_MOD_ID_MCSPI, 0U, NULL);
    }    
    if(S_PASS == status)
    {
        status = PINMUXModuleConfig(CHIPDB_MOD_ID_MCSPI, 1U, NULL);
    }    

    ...
    return BOARD_SOK;
}

這裏的寫法也是跟模塊時鐘使能函數的寫法類似 都是判斷前面一個函數執行成功與否來決定後面的執行與否 只要有一個錯誤 所以這裏調試也要加判斷 萬一前面的出錯 那麼後面的都執行不了

int32_t PINMUXModuleConfig(chipdbModuleID_t moduleId, uint32_t instNum, 
                                                              void* pParam1)
{
    pinmuxModuleCfg_t* pModuleData = NULL;
    pinmuxPerCfg_t* pInstanceData = NULL;
    volatile const pinmuxBoardCfg_t* pPinmuxData  = NULL;
    uint32_t ctrlModBase = CHIPDBBaseAddress(CHIPDB_MOD_ID_CONTROL_MODULE, 0);
    int32_t status = E_FAIL;
    uint32_t index = 0;

    /* Get module Data */
//  pPinmuxData = gGpevmPinmuxData; 

    /* 設置pPinmuxData爲icv2pinux gIceV2PinmuxData有相關單板的引腳設置等 這裏非常重要 */
    pPinmuxData = gIceV2PinmuxData;  
    ASSERT(NULL != pPinmuxData);

    status = E_INVALID_MODULE_ID;
    for(index = 0; ((S_PASS != status) && 
       (CHIPDB_MOD_ID_INVALID != pPinmuxData[index].moduleId)); index++)
    {
        if(pPinmuxData[index].moduleId == moduleId)
        {
            pModuleData = pPinmuxData[index].modulePinCfg;
            ASSERT(NULL != pModuleData);
            status = S_PASS;
        }
    }

    /* Get instance Data */
    if(S_PASS == status)
    {
        status = E_INST_NOT_SUPP;
        for(index = 0; ((S_PASS != status) && 
          (CHIPDB_INVALID_INSTANCE_NUM != pModuleData[index].modInstNum)); index++)
        {
            if(pModuleData[index].modInstNum == instNum)
            {
                pInstanceData = pModuleData[index].instPins;
                ASSERT(NULL != pInstanceData)
                status = S_PASS;
            }
        }
    }

    /* Configure Pinmux */
    if(S_PASS == status)
    {
        for(index = 0; ((uint16_t)PINMUX_INVALID_PIN != 
                                      pInstanceData[index].pinOffset); index++)
        {
            if(NULL != pParam1)
            {
                if(pInstanceData[index].optParam == *(uint16_t*)pParam1)
                {
                    HW_WR_REG32((ctrlModBase + pInstanceData[index].pinOffset),
                                pInstanceData[index].pinSettings);
                    status = S_PASS;
                    break;
                }
            }
            else
            {
                HW_WR_REG32((ctrlModBase + pInstanceData[index].pinOffset),
                                pInstanceData[index].pinSettings);
            }
        }
        if((NULL != pParam1) && ((uint16_t)PINMUX_INVALID_PIN == pInstanceData[index].pinOffset))
        {
            status = E_FAIL;
        }
    }
    /* 將相關的引腳複用 */
    HW_WR_REG32(1155598688,49);
    HW_WR_REG32(1155598692,17);
    /* */
    HW_WR_REG32(1155598736,19); //44E10990 10011
    HW_WR_REG32(1155598740,51);
    HW_WR_REG32(1155598744,51);
    HW_WR_REG32(1155598748,19);

    return status;
}

所以boart_init()主要做了Clock Module Peripheral Registers 外部模塊的時鐘 相關引腳的設置初始化 還要串口的設置初始化之類的工作

然後開始執行spi_test這個函數 這個函數是我們主要做的事情

/*
 *  ======== test function ========
 */
void spi_test(UArg arg0, UArg arg1)
{
    //SPI_Params spiParams;                /* SPI params structure */
    //SPI_Handle handle;                   /* SPI handle */
    SPI_Transaction transaction;         /* SPI transaction */
    int32_t retVal;              /* return value */



    SPI_log("\n McSPI Internal Loopback test app started \n");
    SPI_log("\n The Mode of transfer is Interrupt Mode \n");
     /* Modify the default SPI configurations if necessary */
    /* 修改SPI配置 */
    spi_initConfig();

    /* SPI驅動的初始化 */
    /* Init SPI driver */
    SPI_init();

   /* Open MCSPI instance 1 driver */
   /* 打開SPI驅動 */
    gSpiHandle = SPI_open(MCSPI_INSTANCE, &gSpiParams);
    if(gSpiHandle == NULL)
    {
        printf("\nError opening MCSPI driver\n");
    }
    /* SPI_RX 和SPI_TX的緩衝區初始化 */
    McSPIInitializeBuffers();


    /* 設置transaction結構體 也就是數據傳輸三要素 源 目的 長度 */
    transaction.count = McSPI_DATA_COUNT;
    transaction.txBuf = gTxBuffer;
    transaction.rxBuf = gRxBuffer;
    SPI_transfer(gSpiHandle, &transaction);
    /* 對SPI_RX接受到的數據和SPI_TX發送的數據 比對 如果一致說明spi讀寫成功  */
     retVal = McSPIVerifyData();

    if(retVal != 0)
    {
        SPI_log("\n McSPI Data Transmission is Failed \n");

    }
    else
    {
        SPI_log("\n McSPI Data Transmission is successful \n");
    }
    /* 關閉SPI驅動 */
    SPI_close(gSpiHandle);

    while(1);
}

先是spi_initConfig();執行這個函數

void spi_initConfig(void)
{
    SPI_v1_HWAttrs spi_cfg;
    /* 獲取默認的spi配置 保存在spi_cfg中 */
    /* Get the default UART init configurations */
    SPI_socGetInitCfg(MCSPI_INSTANCE, &spi_cfg);

    /* Modify the default SPI configurations if necessary */
    /* 修改spi_cfg的內容  */
    spi_cfg.dataLineCommMode = MCSPI_DATA_LINE_COMM_MODE_4;

    /* Set the default UART init configurations */
    /* 修改後再寫進去設置 */
    SPI_socSetInitCfg(MCSPI_INSTANCE, &spi_cfg);
}

具體的實現分析 也可以看看

int32_t SPI_socGetInitCfg(uint32_t index, SPI_v1_HWAttrs *cfg)
{
    int32_t ret = 0;

    if (index < CSL_MCSPI_PER_CNT)
    {
        *cfg = spiInitCfg[index];
    }
    else
    {
        ret = -1;
    }
    return ret;
}
/* SPI configuration structure */
SPI_v1_HWAttrs spiInitCfg[CSL_MCSPI_PER_CNT] =
{
    {
        SOC_SPI_0_REGS,
        65,
        91,
        SPI_PINMODE_4_PIN,
        MCSPI_DATA_LINE_COMM_MODE_1,
        MCSPI_CHANNEL_1,
        MCSPI_SINGLE_CH,
        MCSPI_CS_POL_LOW,
        true,
        48000000U,
    },
    {
        SOC_SPI_1_REGS,
        125,
        92,
        SPI_PINMODE_4_PIN,
        MCSPI_DATA_LINE_COMM_MODE_1,
        MCSPI_CHANNEL_0,
        MCSPI_SINGLE_CH,
        MCSPI_CS_POL_LOW,
    true,
        48000000U,
    },
};

所以SPI_socGetInitCfg就是將spiInitCfg[CSL_MCSPI_PER_CNT]內容賦值給spi_cfg中 相反SPI_socSetInitCfg就是將spi_cfg賦值給spiInitCfg[CSL_MCSPI_PER_CNT]中
我們使用的是spi1所以MCSPI_INSTANCE就要設置爲1 這個變量決定了使用spi0還是spi1 我們設置爲1說明使用的是spiInitCfg[1] 看下這個參數的設置

/*!
 *  @brief  SPI_v1 Hardware attributes
 */
typedef struct SPI_v1_HWAttrs_s {
    /*! SPI_v1 Peripheral base address */
    uint32_t baseAddr;
    /*! SPI_v1 Peripheral interrupt vector */
    uint32_t intNum;
    /*! SPI_v1 Peripheral interrupt vector */
    uint32_t eventId;
    /*! pin mode 3 or 4 pin mode */
    uint32_t pinMode;
    /*! data lines mode : which lines are used for tx */
    uint32_t dataLineCommMode;
    /*! Channel number */
    uint32_t chNum;
    /*! Channel mode: Single channel or multi channel */
    uint32_t chMode;
    /*! Polarity of the chip select signal */
    uint32_t csPolarity;
    /*! Polarity of the chip select signal */
    bool enableIntr;
    /*! Module input clock frequency */
    uint32_t inputClkFreq;
} SPI_v1_HWAttrs;

{
        SOC_SPI_1_REGS,
        125,
        92,
        SPI_PINMODE_4_PIN,
        MCSPI_DATA_LINE_COMM_MODE_1,
        MCSPI_CHANNEL_0,
        MCSPI_SINGLE_CH,
        MCSPI_CS_POL_LOW,
    true,
        48000000U,
    },
替換也就是
{
    /*! SPI_v1 Peripheral base address */
    0x481A0000,
    /*! SPI_v1 Peripheral interrupt vector */
    125,
     /*! SPI_v1 Peripheral interrupt vector */
    92,
    /*! pin mode 3 or 4 pin mode */
    SPI_PINMODE_4_PIN,
    uint32_t dataLineCommMode;
    MCSPI_DATA_LINE_COMM_MODE_1,
    /*! Channel mode: Single channel or multi channel */
    MCSPI_CHANNEL_0,
    /*! Polarity of the chip select signal */
    MCSPI_SINGLE_CH,
     /*! Module input clock frequency */
     /**
     * \brief Chip select is held low during active state
     */
    MCSPI_CS_POL_LOW,
    true,
     /*! Module input clock frequency */
    48000000U,
},
/**
 * \brief Communication on Data line pins is configured as :
 *        Data line 0 (SPIDAT[0]) selected for reception
 *        Data line 1 (SPIDAT[1]) selected for transmission
 *        No transmission on Data Line 0 (SPIDAT[0])
 */
#define MCSPI_DATA_LINE_COMM_MODE_1  (((uint32_t) MCSPI_CH0CONF_IS_LINE0 <<     \
                                       MCSPI_CH0CONF_IS_SHIFT) |                \
                                      ((uint32_t) MCSPI_CH0CONF_DPE1_ENABLED << \
                                       MCSPI_CH0CONF_DPE1_SHIFT) |              \
                                      ((uint32_t) MCSPI_CH0CONF_DPE0_DISABLED   \
                                       << MCSPI_CH0CONF_DPE0_SHIFT))
    也就是SPIDAT[0]作爲RX 而SPIDAT[1]作爲TX

/**
 * \brief Communication on Data line pins is configured as :
 *        Data line 1 (SPIDAT[1]) selected for reception
 *        Data line 1 (SPIDAT[1]) selected for transmission
 *        Data Line 0 (SPIDAT[0]) selected for transmission
 */
#define MCSPI_DATA_LINE_COMM_MODE_4  (((uint32_t) MCSPI_CH0CONF_IS_LINE1 <<     \
                                       MCSPI_CH0CONF_IS_SHIFT) |                \
                                      ((uint32_t) MCSPI_CH0CONF_DPE1_ENABLED << \
                                       MCSPI_CH0CONF_DPE1_SHIFT) |              \
                                      ((uint32_t) MCSPI_CH0CONF_DPE0_ENABLED << \
                                       MCSPI_CH0CONF_DPE0_SHIFT))

從上面的配置可以得知MCSPI被設置一下模式
寄存器正確 McSPI1 Registers:0x481A0000

寄存器地址爲0x481A0000
中斷號爲125
eventId爲92
4引腳模式 CLK SPIDAT[0] SPIDAT[1] CS
數據線引腳模式設置爲MCSPI_DATA_LINE_COMM_MODE_1 但是後面會設置爲MCSPI_DATA_LINE_COMM_MODE_4也就是
SPIDAT[0] SPIDAT[1]可以用來發送 但是SPIDAT[1]可以用來接收
MCSPI_CHANNEL_0被選通
單CHANNEL模式 也就是隻使用一個通道 MCSPI_CHANNEL_0
片選CS低電平有效
時鐘頻率爲48000000U

然後就執行SPI_init(void)函數初始化SPI驅動

void SPI_init(void)
{
    if (SPI_count == -1) {
        /* Call each driver's init function */
        for (SPI_count = 0; SPI_config[SPI_count].fxnTablePtr != NULL; SPI_count++) {
            SPI_config[SPI_count].fxnTablePtr->initFxn((SPI_Handle)&(SPI_config[SPI_count]));
        }
    }
}
依次調用SPI_config中SPI_FxnTable_v1的SPI_init_v1函數執行初始化
static void SPI_init_v1(SPI_Handle handle)
{
    /* Input parameter validation */
    OSAL_Assert(handle == NULL);

    /* Mark the object as available */
    ((SPI_v1_Object *)(handle->object))->isOpen = (bool)false;
    SPI_log("\n SPI_init_v1 succeed \n");
}

設置handle->object的isOpen是false 保證SPI在spi_open前未被打開

/* SPI configuration structure */
const SPI_config_list SPI_config = {
    {
        &SPI_FxnTable_v1,
        &SpiObjects[0],
        &spiInitCfg[0]
    },
    {
        &SPI_FxnTable_v1,
        &SpiObjects[1],
        &spiInitCfg[1]
    },
    {
        &QSPI_FxnTable_v1,
        &QspiObjects[0],
        &qspiInitCfg[0]
    },
    /* "pad to full predefined length of array" */
    {NULL, NULL, NULL},
    {NULL, NULL, NULL},
    {NULL, NULL, NULL},
    {NULL, NULL, NULL}
};

所以這裏就會依次調用這裏三個的初始化函數

然後下面的結構體根據“`
/* SPI parameters structure Master mode*/
SPI_Params gSpiParams = {
SPI_MODE_BLOCKING, /* transferMode */
SemaphoreP_WAIT_FOREVER,/* transferTimeout */
NULL, /* transferCallbackFxn */
SPI_MASTER, /* mode */
1000000, /* bitRate */
8, /* dataSize */
SPI_POL0_PHA0, /* frameFormat */
NULL /* custom */
};


就調用SPI_open()
 gSpiHandle = SPI_open(MCSPI_INSTANCE, &gSpiParams);




static SPI_Handle SPI_open_v1(SPI_Handle handle, const SPI_Params *params)
{
    SemaphoreP_Params     semParams;
    uint32_t       key;
    SPI_v1_Object          *object = NULL;
    SPI_v1_HWAttrs const   *hwAttrs = NULL;
    HwiP_Params hwiInputParams;

    uint8_t ret_flag = 0u;
/* 檢查handle是否爲空 爲空就掛起 也就是死循環  */
    /* Input parameter validation */
    OSAL_Assert(handle == NULL);

    /* Get the pointer to the object and hwAttrs */
/* 獲得spi_open函數傳進來的handle裏的object和hwAttrs  */
/* object就是前面SPI_config裏的&SpiObjects[1] 在之前的spi_init中設置了isopen = false */
/* hwAttrs就是SPI_v1_HWAttrs  */
    object = handle->object;
    hwAttrs = handle->hwAttrs;
/* 空函數 ti未編寫此函數 所以什麼都不執行 */
    SPI_osalHwiParamsInit(&hwiInputParams);

    /* Determine if the device index was already opened */
/* 空函數 ti未編寫此函數 所以什麼都不執行 */
    key = SPI_osalHardwareIntDisable();
/* 判斷object->isOpen參數是true or false 前面我們spi_init裏設置裏false 所以這裏執行else部分 */
    if(object->isOpen == true) {
/* 說明已經open過 就不做任何處理 把handle設置爲NULL  */
        SPI_osalHardwareIntRestore(key);
        handle = NULL;
    }
    else
    {
        /* Mark the handle as being used */
/* 把flag設置爲true 代表已經被open 防止被再次open */
        object->isOpen = (bool)true;
/* 空函數 ti未編寫此函數 所以什麼都不執行 */
        SPI_osalHardwareIntRestore(key);

        /* Store the SPI parameters */
/* 判斷params是否爲空 如果爲空就是用默認的params 如果自行設置了 就把object->spiParams賦值爲我們設置的spiParams */
/* 這裏我們只是把transferTimeout 修改爲了SemaphoreP_WAIT_FOREVER 也就是無限等待 默認是0 */
        if (params == NULL) {
            /* No params passed in, so use the defaults */
            SPI_Params_init(&(object->spiParams));
            params = &(object->spiParams);
        }
        else {
            object->spiParams = *params;
        }
/* 判斷params->dataSize是否在4~32內 如果不在就掛起死循環 我們設置的8所以不受這裏影響 */
        OSAL_Assert(!((params->dataSize >= 4) && (params->dataSize <= 32)));

        /* Determine if we need to use an 8-bit or 16-bit framesize for the DMA */
/* 爲DMA設置frameSize爲SPI_v1_8bit或者SPI_v1_16bit 這裏我們是8  所以frameSize設置SPI_v1_8bit */
        object->frameSize = (params->dataSize < 9) ? SPI_v1_8bit : SPI_v1_16bit;



        /* Store the current mode. Extract operating mode from hwAttrs and params */
/* 判斷是否是SPI_MODE_BLOCKING或者SPI_MODE_CALLBACK 我們這裏是SPI_MODE_BLOCKING模式 */
        if(SPI_MODE_BLOCKING == params->transferMode)
        {
/* 設置的true 執行這裏object->operMode保存SPI_OPER_MODE_BLOCKING  */
            if(true == hwAttrs->enableIntr)
            {
              object->operMode = SPI_OPER_MODE_BLOCKING;
            }
            else
            {
              object->operMode = SPI_OPER_MODE_POLLING;
            }
        }
        else
        {
          object->operMode = SPI_OPER_MODE_CALLBACK;
        }


        /* Extract actual mode */
/*  設置object->spiMode爲MCSPI_TX_RX_MODE 爲下面FIFO設置 */
        if(SPI_MASTER == params->mode)
        {
          object->spiMode = MCSPI_TX_RX_MODE;
        }
        else
        {
          object->spiMode = MCSPI_TX_RX_MODE;
        }

/* 前面設置了object->operMode爲SPI_OPER_MODE_BLOCKING 所以這裏執行if */
        if(object->operMode != SPI_OPER_MODE_POLLING)
        {
/* 設置hwiInputParams結構體的相關值並且調用SPI_osalRegisterInterrupt註冊中斷 */
/* 不過在am335x這裏 SPI_osalRegisterInterrupt直接返回了-1的指針 不做任何處理  */
            hwiInputParams.name = NULL;
            hwiInputParams.arg  = (uintptr_t)handle;
            hwiInputParams.priority = 0x20;
            hwiInputParams.evtId = hwAttrs->eventId;
            object->hwi = SPI_osalRegisterInterrupt(hwAttrs->intNum,
                                SPI_v1_hwiFxn, &hwiInputParams);
/* 不執行 */
            if(object->hwi == NULL) {
              SPI_close_v1(handle);
                    ret_flag = 1u;
              handle = NULL;
            }
        }
/* 執行這裏 ret_flag = 0 */
        if(ret_flag == 0u)
        {
          /*
           * Construct thread safe handles for this SPI peripheral
           * Semaphore to provide exclusive access to the QSPI peripheral
           */
   /* am335x對osal不做任何處理 */
          SPI_osalSemParamsInit(&semParams);
          semParams.mode = SemaphoreP_Mode_BINARY;
          object->mutex = SPI_osalCreateBlockingLock(1U, &semParams);

          if (object->operMode == SPI_OPER_MODE_BLOCKING) {
            /*
             * Construct a semaphore to block task execution for the duration of the
             * SPI transfer
             */
            object->transferComplete = SPI_osalCreateBlockingLock(0U, &semParams);

            /* Store internal callback function */
            object->transferCallbackFxn = &SPI_transferCallback_v1;
          }
          if (object->operMode == SPI_OPER_MODE_CALLBACK){
            /* Check to see if a callback function was defined for async mode */
            OSAL_Assert(params->transferCallbackFxn == NULL);

            /* Save the callback function pointer */
            object->transferCallbackFxn = params->transferCallbackFxn;
          }

          object->transaction = NULL;

          /* Extract clock mode from the frame format */
  /* 我們選擇的是SPI_POL0_PHA0 也就是時鐘相位和時鐘極性爲00 */
          switch(params->frameFormat)
          {
            case SPI_POL0_PHA0:
                  object->clockMode = MCSPI_CLK_MODE_0;
            break;

            case SPI_POL0_PHA1:
                  object->clockMode = MCSPI_CLK_MODE_1;
            break;

            case SPI_POL1_PHA0:
                  object->clockMode = MCSPI_CLK_MODE_2;
            break;

            case SPI_POL1_PHA1:
                  object->clockMode = MCSPI_CLK_MODE_3;
            break;

            default:
                  object->clockMode = MCSPI_CLK_MODE_2;
            break;
          }


          /* Reset SPI Peripheral */
  /* 重新設置SPI周圍 這裏都是設置MCSPI_SYSCONFIG的某些位 這裏MCSPI_SYSCONFIG寄存器地址正確110H偏移量  */
          McSPIReset(hwAttrs->baseAddr);
/* 設置MCSPI_SYSCONFIG寄存器的一些值  */
          MCSPISysConfigSetup(hwAttrs->baseAddr, MCSPI_CLOCKS_OCP_ON_FUNC_ON,
                          MCSPI_SIDLEMODE_NO, MCSPI_WAKEUP_DISABLE,
                          MCSPI_AUTOIDLE_OFF);


          /* Configure 3 pin or 4 pin mode */
  /* 我們這裏設置的是SPI_PINMODE_4_PIN 也就是SCLK D0 D1 CS四個pin */
          if(SPI_PINMODE_3_PIN == hwAttrs->pinMode)
          {
            /* Disable chip select pin.*/
            McSPICSDisable(hwAttrs->baseAddr);
          }
          else
          {
            /* Enable chip select pin.*/
/* 設置MCSPI_MODULCTRL寄存器的PIN34爲0  也就是SPIEN is used as a chip select. */
            McSPICSEnable(hwAttrs->baseAddr);
          }
  /* 我們設置的是SPI_MASTER 執行if裏 */
          if(SPI_MASTER == params->mode)
          {
                /* Enable SPI Master */
/* 設置MCSPI_MODULCTRL寄存器的MS爲0  也就是設置爲Master 設置*/
                McSPIMasterModeEnable(hwAttrs->baseAddr);

                /* Configure the peripheral as single channel SPI Master */
/* 設置寄存器設置single channel mode4之類的 設置MCSPI_CH0CONF的IS, DPE0, DPE1爲100 */
                McSPIMasterModeConfig(hwAttrs->baseAddr,
                            hwAttrs->chMode,
                            object->spiMode,
                            hwAttrs->dataLineCommMode,
                            hwAttrs->chNum);
                /* Clock configuration */
/* 時鐘配置*/
                McSPIClkConfig(hwAttrs->baseAddr,
                            hwAttrs->inputClkFreq,
                            params->bitRate,
                            hwAttrs->chNum,
                            object->clockMode);
          }
          else
          {
                /* Enable SPI Slave */
                McSPISlaveModeEnable(hwAttrs->baseAddr);

                /* Configure the peripheral as single channel SPI Master */
                McSPIMasterModeConfig(hwAttrs->baseAddr,
                            hwAttrs->chMode,
                            object->spiMode,
                            hwAttrs->dataLineCommMode,
                            hwAttrs->chNum);
          }

          /* Set word length for corresponding channel */
  /* 設置MCSPI_CH0CONF的WL爲00111 8bits  */
          McSPIWordLengthSet(hwAttrs->baseAddr, MCSPI_WORD_LENGTH(params->dataSize),
                hwAttrs->chNum);

          /* TBC: Below function added for DIAG. Need to check if this needs in any
             special case or generic function. */
          /* Set polarity of SPIEN to low.*/
  /* 設置MCSPI_CH0CONF的EPOL爲1  也即是Set polarity of SPIEN to low */
          McSPICSPolarityConfig(hwAttrs->baseAddr,hwAttrs->csPolarity,
                hwAttrs->chNum);

          /* Enable FIFO's dependent on which mode of operation is chosen */
  /* 前面設置object->spiMode == MCSPI_TX_RX_MODE爲MCSPI_TX_RX_MODE */
          if(object->spiMode == MCSPI_TX_RX_MODE) {
            object->fifoSize = RX_TX_FIFO_SIZE;
/* 寫入寄存器MCSPI_CH0CONF的27位爲1  也就是The buffer is used to transmit data 設置爲發送 */
            McSPITxFIFOConfig(hwAttrs->baseAddr, MCSPI_TX_FIFO_ENABLE,
                  hwAttrs->chNum);
/* 寫入寄存器MCSPI_CH0CONF的28位爲1  也就是The buffer is used to receive data  設置爲接收 */
            McSPIRxFIFOConfig(hwAttrs->baseAddr, MCSPI_RX_FIFO_ENABLE,
                  hwAttrs->chNum);
          }
          else if (object->spiMode == MCSPI_TX_ONLY_MODE) {
            object->fifoSize = 60;
            McSPITxFIFOConfig(hwAttrs->baseAddr, MCSPI_TX_FIFO_ENABLE,
                  hwAttrs->chNum);
            McSPIRxFIFOConfig(hwAttrs->baseAddr, MCSPI_RX_FIFO_DISABLE,
                  hwAttrs->chNum);
          }
          else {
            /* RX_ONLY Mode */
            object->fifoSize = 60;
            McSPITxFIFOConfig(hwAttrs->baseAddr, MCSPI_TX_FIFO_DISABLE,
                  hwAttrs->chNum);
            McSPIRxFIFOConfig(hwAttrs->baseAddr, MCSPI_RX_FIFO_ENABLE,
                  hwAttrs->chNum);
          }
        }
    }
SPI_log("\n SPI_open_v1 succeed \n");
    return (handle);
}   
可見被設置爲BLOCKING 模式
傳送模式是BLOCKING 還有一種是Callback
主模式SPI_MASTER
時序中的時鐘相位和時鐘極性爲SPI_POL0_PHA0 也就是00模式
傳輸數據大小爲8位

然後就是初始化gTxBuffer和gRxBuf```
static void McSPIInitializeBuffers(void)
{
    uint32_t index = 0;

    for (index = 0; index < McSPI_DATA_COUNT; index++)
    {
        /* Initialize the gTxBuffer McSPI1 with a known pattern of data */
            gTxBuffer[index] = index;
        /* Initialize the gRxBuffer McSPI1 with 0 */
        gRxBuffer[index] = (uint32_t) 0;
        /*gRxBuffer被設置爲0 gTxBuffer被設置爲0,1,2....29*/
    }
}

  transaction.count = McSPI_DATA_COUNT;
  transaction.txBuf = gTxBuffer;
  transaction.rxBuf = gRxBuffer;



  static bool SPI_transfer_v1(SPI_Handle handle, SPI_Transaction *transaction)
{
    uint32_t     key;
    SPI_v1_Object    *object = NULL;
   bool ret_val = false;

    /* Input parameter validation */
/* 檢查handle和transaction是否爲空 之前我們設置了 所以這裏不爲空 */
    OSAL_Assert(!((handle != NULL) && (transaction != NULL)));
/* 設置標誌位爲SPI_TRANSFER_STARTED 說明傳輸開始 */
    transaction->status=SPI_TRANSFER_STARTED;
/* transaction->count = 50  */
    if (transaction->count != 0)
    {
        /* Get the pointer to the object */
        object = handle->object;

        /* Check if a transfer is in progress */
        key = SPI_osalHardwareIntDisable();
        if (object->transaction) 
{
          SPI_osalHardwareIntRestore(key);
          transaction->status=SPI_TRANSFER_CANCELED;
  /* Transfer is in progress */
          ret_val = (bool)false;
        }
        else
        {
  /* 保存transaction到object->transaction */
          /* Save the pointer to the transaction */
          object->transaction = transaction;
          /* Acquire the lock for this particular I2C handle */
          SPI_osalPendLock(object->mutex, SemaphoreP_WAIT_FOREVER);

/* 調用這個傳輸函數 前面都是判斷 這個函數纔是真正傳輸數據的功能函數 */
          SPI_primeTransfer_v1(handle, transaction);

          SPI_osalHardwareIntRestore(key);

          if (object->operMode == SPI_OPER_MODE_BLOCKING) 
  {
            SPI_osalPendLock(object->transferComplete, SemaphoreP_WAIT_FOREVER);
          }

          /* Release the lock for this particular I2C handle */
          SPI_osalPostLock(object->mutex);
  /* 發送成功 */
  transaction->status=SPI_TRANSFER_COMPLETED;
  SPI_log("\n SPI_transfer_v1 succeed \n");
          ret_val = (bool)true;
        }
    } 
else
{
   transaction->status=SPI_TRANSFER_CANCELED;
}

    return (ret_val);
}是真正的發送數據功能 




static void SPI_primeTransfer_v1(SPI_Handle handle, SPI_Transaction *transaction)
{
SPI_v1_Object *object = NULL;
SPI_v1_HWAttrs const *hwAttrs = NULL;
uint32_t channelStatus = 0;
uint32_t countIndex;

/* Input parameter validation */
OSAL_Assert(!((handle != NULL) && (transaction != NULL)));

/* Get the pointer to the object and hwAttrs */
hwAttrs = handle->hwAttrs;
object  = handle->object;
/* 賦值 */
object->writeBufIdx = transaction->txBuf;
object->writeCountIdx = transaction->count;

object->readBufIdx = transaction->rxBuf;
object->readCountIdx = transaction->count;

/* Set FIFO XFER levels */
/* object->fifoSize = 32 設置bject->rxTrgLevel和object->txTrgLevel 的大小 */
if (transaction->count <= object->fifoSize) {
    /* Transaction fits entirely in FIFO */
    object->rxTrgLevel = transaction->count;
    object->txTrgLevel = transaction->count;
}
else {
    /*
     * Transaction count is more than FIFO size, set TX trigger level
     * to FIFO size, set RX trigger level to (FIFO size - 2) to prevent
     * TX FIFO under run
     */
    object->rxTrgLevel = object->fifoSize - 2;
    object->txTrgLevel = object->fifoSize;
}
/* MCSPI_XFERLEVEL的AFL和AEL 應該是29  */
McSPIFIFOTrigLvlSet(hwAttrs->baseAddr, object->rxTrgLevel,
                    object->txTrgLevel, object->spiMode);

/* Set number of words to be transmitted */
/*  設置MCSPI_XFERLEVEL的WCNT爲30  傳輸的大小  MCSPI_XFERLEVEL的WCNT應該是30  */
McSPIWordCountSet(hwAttrs->baseAddr, transaction->count);

if(SPI_SLAVE == object->spiParams.mode)
{
    for (countIndex = 0; countIndex < (object->txTrgLevel); countIndex++)
    {
        McSPITransmitData(hwAttrs->baseAddr,
            (uint32_t) (*object->writeBufIdx), hwAttrs->chNum);
        object->writeBufIdx++;
        object->writeCountIdx--;
    }
}

/* Enable the McSPI channel for communication */
/* 設置MCSPI_CHCTRL的EN爲1  也正確 使能Channel0  使能後就開始數據的傳輸 */
McSPIChannelEnable(hwAttrs->baseAddr, hwAttrs->chNum);



/* Interrupt Mode */
if(object->operMode != SPI_OPER_MODE_POLLING)
{
    /* 設置MCSPI_SYST的SSB爲0 設置MCSPI_IRQSTATUS的第0 2 17位爲1 */
    McSPIIntStatusClear(hwAttrs->baseAddr, 
                        MCSPI_INT_TX_EMPTY(hwAttrs->chNum) |
                        MCSPI_INT_RX_FULL(hwAttrs->chNum) | 
                        MCSPI_INT_EOWKE);

    if(SPI_MASTER == object->spiParams.mode)
    {
        /* 將上面設置寄存器的相關位數清0 */
        McSPIIntEnable(hwAttrs->baseAddr, 
                       MCSPI_INT_TX_EMPTY(hwAttrs->chNum) |
                       MCSPI_INT_RX_FULL(hwAttrs->chNum) | 
                       MCSPI_INT_EOWKE);

        /* Assert un-used chip select (Force SPIEN) */
        McSPICSAssert(hwAttrs->baseAddr, hwAttrs->chNum);
    }
    else
    {
        /* 不執行 */
        /* 設置MCSPI_CHCONF的FORCE爲1 */
        McSPIIntEnable(hwAttrs->baseAddr, MCSPI_INT_RX_FULL(hwAttrs->chNum));
    }
}
/* Polling mode */
else
{
    if(SPI_MASTER == object->spiParams.mode)
    {
        /* SPIEN line is forced to low state.*/
        McSPICSAssert(hwAttrs->baseAddr, hwAttrs->chNum);
    }

    /* Polling mode transfer */
    while (0 != object->readCountIdx)
    {
        channelStatus = McSPIChannelStatusGet(hwAttrs->baseAddr,
                                                hwAttrs->chNum);
        if(SPI_MASTER == object->spiParams.mode)
        {
            while (0U == (channelStatus & CSL_MCSPI_CH0STAT_TXS_MASK))
            {
                channelStatus = 0;
                channelStatus = McSPIChannelStatusGet(hwAttrs->baseAddr,
                                                        hwAttrs->chNum);
            }
            McSPITransmitData(hwAttrs->baseAddr,
                (uint32_t) (*object->writeBufIdx), hwAttrs->chNum);
            object->writeBufIdx++;
            object->writeCountIdx--;
        }

        while (0U == (channelStatus & CSL_MCSPI_CH0STAT_RXS_MASK))
        {
            channelStatus = 0;
            channelStatus = McSPIChannelStatusGet(hwAttrs->baseAddr,
                                                    hwAttrs->chNum);
        }
        *object->readBufIdx = (uint8_t)McSPIReceiveData(hwAttrs->baseAddr,
                                                        hwAttrs->chNum);
        (object->readBufIdx)++;
        object->readCountIdx--;

        if(SPI_SLAVE == object->spiParams.mode)
        {
            if (0 != object->writeCountIdx)
            {
                McSPITransmitData(hwAttrs->baseAddr,
                    (uint32_t) (*object->writeBufIdx), hwAttrs->chNum);
                (object->writeBufIdx)++;
                object->writeCountIdx--;
            }
        }
    }

    if(SPI_MASTER == object->spiParams.mode)
    {
        /* Force SPIEN line to the inactive state.*/
        McSPICSDeAssert(hwAttrs->baseAddr, hwAttrs->chNum);
    }

    /* Disable the McSPI channel.*/
    McSPIChannelDisable(hwAttrs->baseAddr, hwAttrs->chNum);

    object->transaction = NULL;
}
}

“`

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章