【STM32L496】使用HAL库实现SPI写入/读取数据(AD5421)

SPI原理

SPI协议详解(图文并茂+超详细)
SPI超详细解析
【STM32笔记】HAL库中的SPI传输(可利用中断或DMA进行连续传输)

AD5421芯片了解

AD5421是一款集成器件,设计用于环路供电型4-20mA智能发射器应用。AD5421在单芯片内提供如下特性和功能:16位DAC和电流放大器,用于对环路电流进行数字控制;用于为整个发射器供电的稳压器;基准电压源;故障报警功能;灵活的SPI兼容型串行接口;增益和失调调整寄存器;以及其它特性和功能。

AD5421为四线制信号芯片,这四个信号线分别为MISO、MOSI、CS、SCLK,即主入从出、主出从入、片选、时钟。片选信号线在有的地方也称SS,其是由主设备控制的,用来确定从机且低电平有效。当编写程序时,通常采用GPIO模拟片选信号(人为拉低pin电平)。
在本文,需要利用AD5421实现写入和读取数据的功能,首先通过芯片手册可以看到,实现写入功能的第八位是0,读取是1。
地址/命令字节功能表
数据格式为8位命令+16位数据(+8位CRC循环校验)
移位寄存器表
AD5421数据传输时序图如下图所示,当SYNC为低电平时有效,此时,当SCLK为下降沿时传输数据,当SYNC为高电平时,输入的数据会锁存。
AD5421数据传输时序图

HAL库配置及初始化

根据芯片手册配置引脚和SPI引脚模式参数,开启中断。
引脚功能表
SPI_GPIO配置
参数设置

中断设置
SPI的片选信号设置为GPIO_Output,低电平有效,传输速度Low
GPIO_Output
配置完成后,同I2C一样,会生成一个SPI 的句柄。

SPI_HandleTypeDef hspi2;

部分代码

通过AD5421实现SPI通信
以下是基于HAL库的SPI收发函数,主要用到HAL_SPI_TransmitHAL_SPI_Receive这两个函数实现,这两个函数相对应的就是HAL_SPI_Transmit_ITHAL_SPI_Receive_IT,这两个函数和前两个函数的差别就是,前者是在阻塞模式下发送和接收消息,而后者是利用中断在非阻塞的模式下发送接收消息,前两个函数无法连续发送或接收消息,而后两个函数可以连续发送或接收消息。除此以外,还有用DMA直接存储模式读写消息,使用示波器也可以看到相关波形,这里没有演示,可以查看文章开头的第三个链接,里面有对这几个函数比较详细的解释。
HAL_GPIO_WritePin (SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET);就是之前一直在讲的软件片选,人为拉高置低电平,启动SPI收发数据。

//this spi's transmisson can not continuous transmission of data.start
int spi_transmit(uint8_t *tpdat,uint16_t tdsize)
{	
	HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET);	
	if(tpdat != NULL || tdsize > 0)
	{
		HAL_SPI_Transmit(&hspi2,tpdat,tdsize,0xFFFF);
		HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET);
		delay_ms(10);
		return 1;
	}
	else
	{
		HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET);
		return 0;
	}
}
int spi_receive(uint8_t *rpdat,uint16_t rdsize)
{
	HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET);	
	if(rpdat != NULL || rdsize > 0)
	{
		HAL_SPI_Receive(&hspi2,rpdat,rdsize,0xFFFF);
		HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET);
		delay_ms(10);
		return 1;
	}
	else
	{
		HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET);
		return 0;
	}
}
//this spi's transmisson can not continuous transmission of data.end

AD5421的读写数据函数,输入移位寄存器为24位(如果需要对数据进行CRC纠错校验,则为32位,这里没用到)。
24/32位字宽的数据在串行时钟输入SCLK的控制下优先载入器件的MSB位,所以在wbuf[1]时需要把data右移八位。
输入移位寄存器由8位地址/命令字节、16位数据字和可选的8位CRC组成。

写序列开始于SYNC信号的下降沿,数据在SCLK下降沿通过SDIN数据线输入。在SYNC上升沿,24位数据被锁存,然后传输到相关的寄存器并执行规定的功能(DAC输出改变或工作模式改变)。

void ad5421_write(uint8_t wadd,uint16_t data)
{
	uint8_t wbuf[3];
	memset(wbuf,0,sizeof(wbuf));
	wbuf[0]=wadd&0x7F;
	wbuf[1]=data>>8;
	wbuf[2]=data&0x00FF;
	spi_transmit(wbuf,3);
}

uint16_t ad5421_read(uint8_t radd)
{
	uint8_t rbuf[3];
	uint8_t read[3];
	memset(rbuf,0,sizeof(rbuf));
	rbuf[0]=radd;
	rbuf[1]=0;
	rbuf[2]=0;
	spi_transmit(rbuf,3);
	
	rbuf[0]=0x09;	
	rbuf[1]=0;	
	rbuf[2]=0;	
	HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_RESET);	
//	HAL_SPI_Transmit(&hspi2,rbuf,1,0xFFFF);
//	HAL_SPI_Receive(&hspi2,rbuf,2,0xFFFF);
	
	HAL_SPI_TransmitReceive(&hspi2,rbuf,read,3,0xFFFF);
	HAL_GPIO_WritePin	(SPI_CS_GPIO_Port,SPI_CS_Pin,GPIO_PIN_SET);	
	
	return (read[1]<<8)|(read[2]&0xFF);
}

在这里有一个函数HAL_SPI_TransmitReceive这个函数是指在阻塞状态下发送或接收一段数据,该函数在文件stm32l4xx_hal_spi.c下。

/**
  * @brief  Transmit and Receive an amount of data in blocking mode.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pTxData pointer to transmission data buffer
  * @param  pRxData pointer to reception data buffer
  * @param  Size amount of data to be sent and received
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,uint32_t Timeout);

遇到的问题

SPI和I2C的代码编写步骤相似,思路也比较相像,但由于SPI读写寄存器这个完成了有一段时间了,所以遇到了什么问题其实印象有点模糊了,如果想到什么再加吧。
后面在实现读芯片温度和读VLoop功能时有遇到过问题,下文再述。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用STM32L433 HAL库进行SPI转发的步骤: 1. 首先,需要在CubeMX中配置SPI接口和GPIO引脚。在Pinout & Configuration选项卡中,将SPI接口和GPIO引脚与SPI总线连接起来。 2. 在代码中,需要包含SPI和GPIO的头文件,并初始化SPI和GPIO。 ```c #include "stm32l4xx_hal.h" #include "spi.h" #include "gpio.h" SPI_HandleTypeDef hspi1; void MX_SPI1_Init(void) { /* SPI1 parameter configuration*/ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi1) != HAL_OK) { Error_Handler(); } } void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); /*Configure GPIO pin : PA4 */ GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` 3. 在代码中,需要编写SPI转发函数。该函数将从一个SPI总线接收数据,并将其发送到另一个SPI总线。 ```c void SPI_TransmitReceive(SPI_HandleTypeDef *hspi_rx, SPI_HandleTypeDef *hspi_tx) { uint8_t data_rx[1]; uint8_t data_tx[1]; // 从SPI1接收数据 HAL_SPI_Receive(hspi_rx, data_rx, 1, 1000); // 将数据发送到SPI2 data_tx[0] = data_rx[0]; HAL_SPI_Transmit(hspi_tx, data_tx, 1, 1000); } ``` 4. 在主函数中,需要初始化SPI和GPIO,并调用SPI转发函数。 ```c int main(void) { HAL_Init(); MX_GPIO_Init(); MX_SPI1_Init(); MX_SPI2_Init(); while (1) { SPI_TransmitReceive(&hspi1, &hspi2); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值