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;}}
“`
- TI-RTOS-SPI深度解析
- [TIRTOS--Introduction]TI RTOS Kernel
- CC3200 TI RTOS LPDS模式
- TI 硬件SPI调试
- [TIRTOS--Introduction]TI RTOS User Guide
- 基于TI-RTOS的CC2640 UART
- CC2640R2F BLE5.0 TI-RTOS概述
- 基于TI-RTOS的CC2640 UART
- CCS v6.1下完成TI-RTOS配置
- TI-RTOS Sys-Bios操作系统:Hwi创建方法
- TI-RTOS Sys-Bios操作系统:task栈溢出检测方法
- [TIRTOS--Introduction]TI RTOS简介与初步了解
- CCS v6.1下完成TI-RTOS配置
- 基于TI-RTOS的CC2650DK开发(2)---点亮LED
- 基于TI-RTOS的CC2650DK开发(5)---线程概览
- 基于TI-RTOS的CC2650DK开发(6)---硬件中断
- 基于TI-RTOS的CC2650DK开发(7)---软件中断
- 基于TI-RTOS的CC2650DK开发(8)---任务
- Hinton Neural Networks课程笔记2b:第一代神经网络之感知机
- vue2.0脚手架的webpack 配置文件分析
- 利用tomcat启动本地jsp页面
- [JavaEE
- APUE第七章 进程环境
- TI-RTOS-SPI深度解析
- 18.odoo入门——odoo权限控制(一)模型(数据表)级别权限控制
- 公式摘录
- 利用 uic.exe 手动生成ui头文件
- VS2010中单文档/多文档程序----状态栏操作
- Android开源框架Universal-Image-Loader的详情讲解
- vxworks常用API总结
- linux如何查看一段时间的日志sed和grep的使用
- Qt软件开发文档15---聊天窗口的实现(2),QTextEdit+QPainter实现聊天框自适应大小