这次来记录下SPI总线的过程
SPI分为4根线 NSS,MOSI,MISO,SCK。连接方式如下
SCK: 时钟线,时钟信号线,用于通讯数据同步。它由通讯主机产生,决定了通
讯的速率,不同的设备支持的最高时钟频率不一样,如 STM32 的 SPI 时钟频率最大为
fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。
MOSI:主发从收线
MISO 主收从发线
NSS :也叫CS,片选,可以用内部也可以用外部。大多数情况都是用外部CS。SPI 协议中没有设备地址,它使用 NSS 信
号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从
设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以
SPI 通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号
参考野火教程上的资料
SPI一共有4中通讯模式,分别是时钟极性 CPOL和时钟相位 CPHA
1.时钟极性 CPOL 是指 SPI 通讯设备处于空闲状态时, SCK 信号线的电平信号(即 SPI 通
讯开始前、 NSS 线为高电平时 SCK 的状态)。 CPOL=0 时, SCK 在空闲状态时为低电平,
CPOL=1 时,则相反。
2.时钟相位 CPHA 是指数据的采样的时刻,当 CPHA=0 时, MOSI 或 MISO 数据线上的
信号将会在 SCK 时钟线的“奇数边沿‖被采样。当 CPHA=1 时,数据线在 SCK 的“偶数边
沿‖采样
一般用的比较多的是模式0和模式3。主机和从机通讯时候一定要确定是那种模式。
由于SPI的特性,一个时钟到来的时候,发和收在一个时钟下进行,因此在发数据的同时也可以接收到数据,是全双工通信。
来看下软件代码,用AD5624芯片,这是一个控制DAC芯片输出的。首先看下stm32用HAL库的
/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi3;
/**
-
@brief SPI MSP Initialization
-
This function configures the hardware resources used in this example
-
@param hspi: SPI handle pointer
-
@retval None
/
void HAL_SPI_MspInit(SPI_HandleTypeDef hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(hspi->Instance==SPI3)
{
/* USER CODE BEGIN SPI3_MspInit 0 *//* USER CODE END SPI3_MspInit 0 /
/* Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI3;
PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
// Error_Handler();
}/* Peripheral clock enable */
__HAL_RCC_SPI3_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();
/**SPI3 GPIO Configuration
PC10 ------> SPI3_SCK
PC12 ------> SPI3_MOSI
PC11 ------> SPI3_MISO
*/
GPIO_InitStruct.Pin = DAC_SCK_Pin|DAC_MOSI_Pin;
// GPIO_InitStruct.Pin = DAC_SCK_Pin|DAC_NSS_Pin|DAC_MISO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/* USER CODE BEGIN SPI3_MspInit 1 */
/* USER CODE END SPI3_MspInit 1 */
}
}
/**
-
@brief SPI MSP De-Initialization
-
This function freeze the hardware resources used in this example
-
@param hspi: SPI handle pointer
-
@retval None
/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef hspi)
{
if(hspi->Instance==SPI3)
{
/* USER CODE BEGIN SPI3_MspDeInit 0 *//* USER CODE END SPI3_MspDeInit 0 /
/ Peripheral clock disable */
__HAL_RCC_SPI3_CLK_DISABLE();/**SPI3 GPIO Configuration
PC10 ------> SPI3_SCK
PC12 ------> SPI3_MOSI
PC11 ------> SPI3_MISO
*/
HAL_GPIO_DeInit(GPIOC, DAC_SCK_Pin|DAC_MOSI_Pin);/* USER CODE BEGIN SPI3_MspDeInit 1 */
/* USER CODE END SPI3_MspDeInit 1 */
}
}
/**
- @brief DACµÄ³õʼ»¯
- @param None
- @retval None
*/
void BSP_InitDAC(void)
{
MX_SPI3_Init();
}
/**
- @brief SPI3 Initialization Function
- @param None
- @retval None
*/
static void MX_SPI3_Init(void)
{
/* USER CODE BEGIN SPI3_Init 0 */
/* USER CODE END SPI3_Init 0 */
/* USER CODE BEGIN SPI3_Init 1 */
/* USER CODE END SPI3_Init 1 /
/ SPI3 parameter configuration*/
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_MASTER;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi3.Init.NSS = SPI_NSS_SOFT;
hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 7;
// hspi3.Init.NSSPMode = SPI_NSS_PULSE_ENABLE; //Ôʼ(»áÓ°Ïìµ½SPI·¢ËÍÊý¾ÝÅäÆ«Ñ¹Ê§°Ü)
hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; // /* ½ûÖ¹Âö³åÊä³ö */0803 ¸üÐÂ
hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
// hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
// hspi3.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
// hspi3.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
// hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
// hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
// hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
// hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
// hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE; //Ôʼ£¨x£©
hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;/* ½ûÖ¹SPIºó£¬SPIÏà¹ØÒý½Å±£³Öµ±Ç°×´Ì¬ / //0803 ¸üÐÂ
// hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
Error_Handler();
}
/ USER CODE BEGIN SPI3_Init 2 */
/* USER CODE END SPI3_Init 2 */
}
/**
- @brief ·¢ËÍ1¸ö×Ö½Ú
- @param Ò»¸ö×Ö½ÚµÄÊý¾Ý
- @retval None
- @note
*/
void SPI_WriteByte(uint8_t data)
{
// uint8_t pdata =&data;
HAL_SPI_Transmit(&hspi3,&data,1,10);
/ дÈëÊý¾Ý¼Ä´æÆ÷£¬°ÑҪдÈëµÄÊý¾ÝдÈë·¢ËÍ»º³åÇø */
}
/**
-
@brief DACд
-
@param DACдµÄÊý¾Ý
-
@retval None
-
@note Ä£ÄâSPI·¢ËÍ
*/
void SPI_WriteDAC(uint16_t data)
{
uint16_t *pdata;
uint8_t tempData[2];
uint16_t ConvertData;
tempData[1]=((data >> 8) & 0x0000FF); //¸ß8λ
tempData[0]=((data >> 0) & 0x0000FF); //µÍ8λConvertData=tempData[1];
ConvertData=(ConvertData<<8)+tempData[0];pdata=&ConvertData;
// pdata=&data;
DAC_SYNC(0x01);
HAL_Delay(1);
// delay_us(10);
DAC_SYNC(0x00);
HAL_Delay(1);
// delay_us(10);
HAL_SPI_Transmit(&hspi3, (uint8_t *)pdata,1,10);
// delay_us(10);
DAC_SYNC(0x01);
}
void AD5624_WriteDAC(uint32_t data)
{
DAC_SYNC(0x01);
// delay_us(10);
HAL_Delay(1);
DAC_SYNC(0x00);
// delay_us(10);
HAL_Delay(1);
SPI_WriteByte((data >> 16) & 0x0000FF);
SPI_WriteByte((data >> 8) & 0x0000FF);
SPI_WriteByte((data >> 0) & 0x0000FF);
// delay_us(10);
HAL_Delay(1);
DAC_SYNC(0x01);
}
再来看下GD32的
/*!
\brief configure the RCU of peripherals
\param[in] none
\param[out] none
\retval none
/
static void DAC_rcu_config(void)
{
/ enable the clock of peripherals */
rcu_periph_clock_enable(BOARD_DAC_GPIO_RCU);
rcu_periph_clock_enable(BOARD_DAC_RCU );
}
/*!
\brief configure the related GPIO
\param[in] none
\param[out] none
\retval none
/
void gpio_config(void)
{
/ once enabled the DAC, the corresponding GPIO pin is connected to the DAC converter automatically */
gpio_mode_set(BOARD_DAC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_PULLDOWN, BOARD_DAC_GPIO_PIN);
gpio_output_options_set(BOARD_DAC_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,BOARD_DAC_GPIO_PIN);
}
/**
-
@brief ³õʼ»¯ÄÚ²¿DAC
-
@param None
-
@retval None
-
@note
/
void InterDAC_Config(void)
{
DAC_rcu_config();
gpio_config();
/ configure the DAC0 */
dac_trigger_source_config(DAC0, DAC_TRIGGER_SOFTWARE);
dac_trigger_enable(DAC0);
dac_wave_mode_config(DAC0, DAC_WAVE_DISABLE);
dac_lfsr_noise_config(DAC0, DAC_LFSR_BITS10_0);
dac_output_buffer_disable(DAC0);/* configure the DAC1 */
dac_trigger_source_config(DAC1, DAC_TRIGGER_SOFTWARE);
dac_trigger_enable(DAC1);
dac_wave_mode_config(DAC1, DAC_WAVE_DISABLE);
dac_lfsr_noise_config(DAC1, DAC_LFSR_BITS10_0);
dac_output_buffer_disable(DAC1);
// /* enable DAC concurrent mode and set data */
}
/**
- @brief ÅäÖÃÄÚ²¿DAC1µçѹ
- @param ÅäÖõçѹֵ
- @retval None
- @note
*/
void Set_DAC1(uint16_t value)
{
if(value < 4096)
{
dac_data_set(DAC0,DAC_ALIGN_12B_R,value);
dac_concurrent_software_trigger_enable();
}
}
/**
- @brief ÅäÖÃÄÚ²¿DAC2µçѹ
- @param ÅäÖõçѹֵ
- @retval None
- @note
*/
void Set_DAC2(uint16_t value)
{
if(value < 4096)
{
dac_data_set(DAC1,DAC_ALIGN_12B_R,value);
dac_concurrent_software_trigger_enable();
}
}
/**
- @brief DACÄÚ²¿²Î¿¼µçѹ
- @param None
- @retval None
- @note
*/
void AD5624InterVref()
{
AD5624_WriteDAC(0x380001);
}
/**
- @brief DAC¸´Î»
- @retval None
- @note
*/
void AD5624SoftReset()
{
AD5624_WriteDAC(0x280001);
}
/**
- @brief ·¢ËÍ1¸ö×Ö½Ú
- @param Ò»¸ö×Ö½ÚµÄÊý¾Ý
- @retval None
- @note
/
void SPI_WriteByte(uint8_t data)
{
/ loop while data register in not emplty */
spi_i2s_data_transmit(SPI2,data);
while(RESET == spi_i2s_flag_get(SPI2,SPI_FLAG_TBE));
}
void AD5624_WriteDAC(uint32_t data)
{
DAC_SYNC(0x01);
delay_us(10);
DAC_SYNC(0x00);
delay_us(10);
SPI_WriteByte((data >> 16) & 0x0000FF);
SPI_WriteByte((data >> 8) & 0x0000FF);
SPI_WriteByte((data >> 0) & 0x0000FF);
delay_us(10);
DAC_SYNC(0x01);
}
//void SPI_WriteByte(uint8_t data)
//{
// uint8_t i=0;
//
// DAC_CLK(1);
// delay_1us(1);
// for(i=0;i<8;i++)
// {
// DAC_CLK(0);
// delay_1us(1);
// if((data&0x80)==0x80)
// {
// DAC_DIN(1);
// }
// else
// {
// DAC_DIN(0);
// }
//
// delay_1us(1);
// DAC_CLK(1);
// delay_1us(1);
// data<<=1;
// }
//}
/**
- @brief DACд
- @param DACдµÄÊý¾Ý
- @retval None
- @note Ä£ÄâSPI·¢ËÍ
*/
void SPI_WriteDAC(uint16_t data)
{
DAC_SYNC(0x01);
delay_us(10);
DAC_SYNC(0x00);
delay_us(10);
// SPI_WriteByte((data >> 16) & 0x0000FF);
SPI_WriteByte((data >> 8) & 0x0000FF);
SPI_WriteByte((data >> 0) & 0x0000FF);
delay_us(10);
DAC_SYNC(0x01);
}
/**
-
@brief DAC³õʼ»¯
-
@param None
-
@retval None
-
@note
*/
void DAC_Config()
{
/ÍⲿDAC³õʼ»¯/
// AD5624InterVref(); //ÄÚ²¿»ù×¼/ÄÚ²¿DAC³õʼ»¯/
// InterDAC_Config();
}