TI-RTOS-SPI深度解析

来源:互联网 发布:水池结构设计软件 编辑:程序博客网 时间:2024/06/07 22:07
开发板:AM335X编译环境:cssqq:956465349gdut15级本科

最近在移植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;}}

“`

原创粉丝点击