开发板: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 */
/* *