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;
}
}

“`

你可能感兴趣的:(RTOS)