/*
* Create the table of options which are processed to get/set the device
* options. These options are table driven to allow easy maintenance and
* expansion of the options.
*/
typedef struct
{
u32 Option;
u32 Mask;
} OptionsMap;
static OptionsMap OptionsTable[] =
{
// 主机模式选项
{XSPIPS_MASTER_OPTION, XSPIPS_CR_MSTREN_MASK},
// 极性(CLK_POL)配置选项
// CPOL的高低决定串行同步时钟的空闲状态电平,CPOL = 0,为低电平
{XSPIPS_CLK_ACTIVE_LOW_OPTION, XSPIPS_CR_CPOL_MASK},
// 时钟相位(CLK_PH)配置选项
// CPHA的高低决定串行同步时钟是在第一时钟跳变沿还是第二个时钟跳变沿数据被采集,当CPHL = 0,在第一个跳变沿进行数据采集;
{XSPIPS_CLK_PHASE_1_OPTION, XSPIPS_CR_CPHA_MASK},
// 是否使用 3/8 译码器 ,从3个SS信号扩展到8个SS信号 配置选项
{XSPIPS_DECODE_SSELECT_OPTION, XSPIPS_CR_SSDECEN_MASK},
// 强制选择模式,通过调用发送函数来强制选择CS来使CS有效。
{XSPIPS_FORCE_SSELECT_OPTION, XSPIPS_CR_SSFORCE_MASK},
// 手动触发选项
{XSPIPS_MANUAL_START_OPTION, XSPIPS_CR_MANSTRTEN_MASK}
};
s32 XSpiPs_SetOptions(XSpiPs *InstancePtr, u32 Options)
{
u32 ConfigReg;
u32 Index;
u32 CurrentConfigReg;
s32 Status;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
/*
* Do not allow the slave select to change while a transfer is in
* progress. Not thread-safe.
*/
// 在传输过程中,不允许该改变从机选择,线程不安全
if (InstancePtr->IsBusy == TRUE)
{
Status = (s32)XST_DEVICE_BUSY;
}
else
{
// 读取当前寄存器配置信息
ConfigReg = XSpiPs_ReadReg( InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET );
// 将当前配置赋值给 CurrentConfigReg
CurrentConfigReg = ConfigReg;
/*
* Loop through the options table, turning the option on or off
* depending on whether the bit is set in the incoming options flag.
*/
// 循环遍历选项表,打开或关闭选项
// 取决于是否在传入选项标志中设置了位
for (Index = 0U; Index < XSPIPS_NUM_OPTIONS; Index++)
{
if ((Options & OptionsTable[Index].Option) != (u32)0U)
{
/* Turn it on */
ConfigReg |= OptionsTable[Index].Mask;
}
else
{
/* Turn it off */
ConfigReg &= ~(OptionsTable[Index].Mask);
}
}
/*
* If CPOL-CPHA bits are toggled from previous state,
* disable before writing the configuration register and then enable.
*/
// 配置 CPOL/CPHA 选项时,先禁止 SPI 再使能
if( ((CurrentConfigReg & XSPIPS_CR_CPOL_MASK) !=
(ConfigReg & XSPIPS_CR_CPOL_MASK)) ||
((CurrentConfigReg & XSPIPS_CR_CPHA_MASK) !=
(ConfigReg & XSPIPS_CR_CPHA_MASK)) )
{
XSpiPs_Disable(InstancePtr);
}
/*
* Now write the Config register. Leave it to the upper layers
* to restart the device.
*/
// 将配置写入到寄存器,请在 应用层 重启 SPI
XSpiPs_WriteReg(InstancePtr->Config.BaseAddress,
XSPIPS_CR_OFFSET, ConfigReg);
/*
* Enable
*/
// 配置 CPOL/CPHA 选项时,先禁止 SPI 再使能
if( ((CurrentConfigReg & XSPIPS_CR_CPOL_MASK) !=
(ConfigReg & XSPIPS_CR_CPOL_MASK)) ||
((CurrentConfigReg & XSPIPS_CR_CPHA_MASK) !=
(ConfigReg & XSPIPS_CR_CPHA_MASK)) )
{
XSpiPs_Enable(InstancePtr);
}
Status = (s32)XST_SUCCESS;
}
return Status;
}