開發板: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;
}
}
“`