- 开发板:AM335X
- 编译环境:css
- qq:956465349
- gdut15级本科
复制代码
最近在移植rtos的spi-loopback的测试程序到am335x开发板上 顺便把相关的操作函数源码给分析了下
移植的是pdk_am335x_1_0_5packagestidrvspiexamplemcspiLoopbackApp的测试程序
一开始跑的肯定是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_cros***arInit();
- #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 drivern");
- }
- /* 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);
- }
复制代码
|