stm32h7高速通信_【STM32H7教程】第75章 STM32H7的SPI总线应用之驱动DAC8501(双路输出,16bit分辨率,0-5V)...

本文详细介绍了如何使用STM32H7的SPI总线驱动DAC8501,包括中断和DMA两种方式。内容涵盖SPI配置、DAC8501硬件设计、时序要求、驱动设计步骤,以及中断和DMA传输的实现。还提供实验例程说明,帮助读者理解DAC8501的SPI DMA驱动方式。
摘要由CSDN通过智能技术生成

第75章       STM32H7的SPI总线应用之驱动DAC8501(双路输出,16bit分辨率,0-5V)

本章节为大家讲解标准SPI接线方式驱动模数转换器DAC8501,制作了中断和DMA两种驱动方式。

75.1 初学者重要提示

75.2 DAC结构分类和技术术语

75.3 DAC8501硬件设计

75.4 DAC8501关键知识点整理(重要)

75.5 DAC8501驱动设计(中断更新方式)

75.5 DAC8501驱动设计(SPI DMA更新方式)

75.6 SPI总线板级支持包(bsp_spi_bus.c)

75.7 DAC8501支持包中断方式(bsp_spi_dac8501.c)

75.8 DAC8501支持包DMA方式(bsp_spidma_dac8501.c)

75.9 DAC8501驱动移植和使用(中断更新方式)

75.10 DAC8501驱动移植和使用(SPI DMA更新方式)

75.11 实验例程设计框架

75.12 实验例程说明(MDK)

75.13 实验例程说明(IAR)

75.14 总结

75.1 初学者重要提示

1、  学习本章节前,务必优先学习第72章。

2、  DAC8501模块上带了两片8501,每片是单通道DAC,带片上输出缓冲运放,轨到轨输出,16bit分辨率,支持30MHz的SPI时钟速度。

3、  本章涉及到的知识点比较多,需要大家掌握STM32H7的SPI , DMA,TIM,DMAMUX和DAC8501的一些细节用法。

4、 H7的SPI + DMA驱动这类外设的灵活度,绝对可以媲美FPGA去控制:

H7的SPI外设比F4系列的灵活性强太多了,主要表现在两个方面:数据的传输支持了4-32bit,特别是那个NSS片选引脚,超强劲,可以做各种时间插入,灵活应对了市场上这类芯片的需求。

DMA这块相比F4系列,有了质的飞跃,支持了DMAMUX,这个DMAMUX除了带来灵活的触发源选择,还支持了各种触发事件和同步触发功能。本章配套例子的触发周期控制就是利用了DMAMUX的同步触发功能。

5、  本章配套了中断和DMA两种更新方式的案例,DMA实现方式与中断更新方式完全不同,因为DMA方式要使用硬件SPI1 NSS片选引脚驱动DAC8501。而中断更新方式使用公共的总线驱动文件bsp_spi_bus.c,片选是通过通用IO方式控制,支持串行FLASH、TSC2046、VS1053、AD7705、ADS1256等SPI设备。大家在看例子的时候要注意。

6、  对于本章教程配套例子的SPI DMA方式,这里特别注意一点,定时器触发一次,就会让SPI以DMA方式传输24bit数据。

7、  DAC8501数据手册,模块原理图和接线图都已经放到本章教程配置例子的Doc文件里。

75.2 DAC结构分类和技术术语

在本教程的第74章进行了详细说明。

75.3 DAC8501硬件设计

DAC的原理图下载:

75.3.1 DAC8501模块规格

产品规格:

1、供电电压: 2.7 - 5.5V【3.3V供电时,输出电压也可以到5V】。

2、通道数: 2路  (通过2片DAC8501E实现)。

3、输出电压范围 : 0 - 5V【零位 < 0.020V, 满位 > 4.970V】。

4、分辨率: 16位。

5、功耗 :  小于10mA。

6、MCU接口 :高速 SPI (30M) 支持 3.3V和5V单片机。

7、DAC输出模拟带宽:350KHz。

8、DAC输出响应: 10uS 到 0.003% FSR。

产品特点:

1、输出和供电电压无关;模块内带升压电路和5V基准。

2、自适应单片机的电平(2.7 - 5V 均可以)。

3、输出电压轨到轨,最高电压可以到 4.970V 以上。

产品效果:

bb0b84541dbe2dc4f3faeffe7bc79e8a.png

5712a96a4d77ac16ea6048ee8f2e087c.png

75.3.2 DAC8501硬件接口

V7板子上DAC8501模块的插座的原理图如下:

707197733f4e056d721ae7caa189ea11.png

实际对应开发的位置如下:

79fdb013e785cc07380e99500a419f36.png

75.4 DAC8501关键知识点整理(重要)

驱动DAC8501需要对下面这些知识点有个认识。

75.4.1 DAC8501基础信息

单通道DAC,带片上输出缓冲运放,轨到轨输出,16bit分辨率,支持30MHz的SPI时钟速度。

模拟输出带宽350KHz。

供电范围2.7V到5.5V。

具有低功耗特性。

上电复位输出0V。

dea0111bc244b8255577bcde4ad41e0c.png

75.4.2 DAC8501每个引脚的作用

DAC8501的封装形式:

bd8d2837b05a5ba1224529884b9dd8af.png

Vdd

供电范围2.7-5.5V。

Vref

稳压基准输入。

Vfb

输出运放的反馈。

Vout

模拟输出电压,输出运放具有轨到轨特性。

SYNC (片选)

低电平有效,当SYNC变为低电平时,它使能输入移位寄存器,并且数据采样在随后的时钟下降沿。 DAC输出在第24个时钟下降沿之后更新。 如果SYNC在第23个时钟沿之前变高,SYNC的上升沿将充当中断,并且DAC8501将忽略写序列。

SCLK

时钟输入端,支持30MHz。

Din

串行时钟输入,每个时钟下降沿将数据写到的24bit的输入移位寄存器。

GND

接地端。

75.4.3 DAC8501输出电压计算公式

DAC8501的计算公式如下:

e246e15f44ceb7cf03d4494d82e7ba19.png

D

配置DAC8501数据输出寄存器的数值,范围0 到2^16 – 1,即0到65535。

VREF

使用外部参考电压,由VREFIN引脚的输入决定。

Vout

输出电压。

75.4.4 DAC8501时序图

DAC8501的时序图如下:

2c828721bcf9e3eac5d0583eb6197aee.png

06c67dbbb8b75a32b4e4efa7db427c92.png

这个时序里面有三个参数尤其重要,后面时序配置要用到。

f(1)

供电2.7到3.6V时,最高时钟20MHz。

供电3.6到5.5V时,最高时钟30MHz。

t(4)

SYNC低电平有效到SCLK第1个上降沿信号的时间没有最小值限制,可以为0。

t(8)

每传输24bit数据后,SYNC要保持一段时间的高电平。

供电2.7到3.6V时,最小要求50ns。

供电3.6到5.5V时,最小要求33ns。

75.4.5 DAC8501寄存器配置

DAC8501的寄存器配置是24bit格式:

b1260f335d84f96e7681ef5388ad004b.png

控制DAC8501每次要传输24bit数据,高8bit控制位 + 16bit数据位。

控制位的PD1和PD0定义如下:

ac750f69122291c468e6fcdf4709a3cd.png

PD1 PD0 决定4种工作模式

0   0  ---> 正常工作模式

0   1  ---> 输出接1K欧到GND

1   0  ---> 输出100K欧到GND

1   1  ---> 输出高阻

75.5 DAC8501驱动设计(中断更新方式)

DAC8501的程序驱动框架设计如下:

167732580a7b97e846adb8d15d1f7945.png

有了这个框图,程序设计就比较好理解了。

75.5.1 第1步:SPI总线配置

spi总线配置通过如下两个函数实现:

/**********************************************************************************************************

* 函 数 名: bsp_InitSPIBus

* 功能说明: 配置SPI总线。

* 形 参: 无

* 返 回 值: 无

**********************************************************************************************************/

void bsp_InitSPIBus(void)

{

g_spi_busy= 0;

bsp_InitSPIParam(SPI_BAUDRATEPRESCALER_8, SPI_PHASE_1EDGE, SPI_POLARITY_LOW);

}/**********************************************************************************************************

* 函 数 名: bsp_InitSPIParam

* 功能说明: 配置SPI总线参数,时钟分频,时钟相位和时钟极性。

* 形 参: _BaudRatePrescaler SPI总线时钟分频设置,支持的参数如下:

* SPI_BAUDRATEPRESCALER_2 2分频

* SPI_BAUDRATEPRESCALER_4 4分频

* SPI_BAUDRATEPRESCALER_8 8分频

* SPI_BAUDRATEPRESCALER_16 16分频

* SPI_BAUDRATEPRESCALER_32 32分频

* SPI_BAUDRATEPRESCALER_64 64分频

* SPI_BAUDRATEPRESCALER_128 128分频

* SPI_BAUDRATEPRESCALER_256 256分频

*

* _CLKPhase 时钟相位,支持的参数如下:

* SPI_PHASE_1EDGE SCK引脚的第1个边沿捕获传输的第1个数据

* SPI_PHASE_2EDGE SCK引脚的第2个边沿捕获传输的第1个数据

*

* _CLKPolarity 时钟极性,支持的参数如下:

* SPI_POLARITY_LOW SCK引脚在空闲状态处于低电平

* SPI_POLARITY_HIGH SCK引脚在空闲状态处于高电平

*

* 返 回 值: 无

**********************************************************************************************************/

voidbsp_InitSPIParam(uint32_t _BaudRatePrescaler, uint32_t _CLKPhase, uint32_t _CLKPolarity)

{/*提高执行效率,只有在SPI硬件参数发生变化时,才执行HAL_Init*/

if (s_BaudRatePrescaler == _BaudRatePrescaler && s_CLKPhase == _CLKPhase && s_CLKPolarity ==_CLKPolarity)

{return;

}

s_BaudRatePrescaler=_BaudRatePrescaler;

s_CLKPhase=_CLKPhase;

s_CLKPolarity=_CLKPolarity;/*设置SPI参数*/hspi.Instance= SPIx; /*例化SPI*/hspi.Init.BaudRatePrescaler= _BaudRatePrescaler; /*设置波特率*/hspi.Init.Direction= SPI_DIRECTION_2LINES; /*全双工*/hspi.Init.CLKPhase= _CLKPhase; /*配置时钟相位*/hspi.Init.CLKPolarity= _CLKPolarity; /*配置时钟极性*/hspi.Init.DataSize= SPI_DATASIZE_8BIT; /*设置数据宽度*/hspi.Init.FirstBit= SPI_FIRSTBIT_MSB; /*数据传输先传高位*/hspi.Init.TIMode= SPI_TIMODE_DISABLE; /*禁止TI模式*/hspi.Init.CRCCalculation= SPI_CRCCALCULATION_DISABLE; /*禁止CRC*/hspi.Init.CRCPolynomial= 7; /*禁止CRC后,此位无效*/hspi.Init.CRCLength= SPI_CRC_LENGTH_8BIT; /*禁止CRC后,此位无效*/hspi.Init.NSS= SPI_NSS_SOFT; /*使用软件方式管理片选引脚*/hspi.Init.FifoThreshold= SPI_FIFO_THRESHOLD_01DATA; /*设置FIFO大小是一个数据项*/hspi.Init.NSSPMode= SPI_NSS_PULSE_DISABLE; /*禁止脉冲输出*/hspi.Init.MasterKeepIOState= SPI_MASTER_KEEP_IO_STATE_ENABLE; /*禁止SPI后,SPI相关引脚保持当前状态*/hspi.Init.Mode= SPI_MODE_MASTER; /*SPI工作在主控模式*/

/*复位配置*/

if (HAL_SPI_DeInit(&hspi) !=HAL_OK)

{

Error_Handler(__FILE__, __LINE__);

}/*初始化配置*/

if (HAL_SPI_Init(&hspi) !=HAL_OK)

{

Error_Handler(__FILE__, __LINE__);

}

}

关于这两个函数有以下两点要做个说明:

函数bsp_InitSPIBus里面的配置是个初始设置。实际驱动芯片时,会通过函数bsp_InitSPIParam做再配置。

函数bsp_InitSPIParam提供了时钟分频,时钟相位和时钟极性配置。驱动不同外设芯片时,基本上调整这三个参数就够。当SPI接口上接了多个不同类型的芯片时,通过此函数可以方便的切换配置。

75.5.2 第2步:SPI总线的查询,中断和DMA方式设置

注:对于DAC8501,请使用查询方式。

SPI驱动的查询,中断和DMA方式主要通过函数bsp_spiTransfer实现数据传输:

/**********************************************************************************************************

* 选择DMA,中断或者查询方式

**********************************************************************************************************/

//#define USE_SPI_DMA /* DMA方式 *///#define USE_SPI_INT /* 中断方式 */

#define USE_SPI_POLL /* 查询方式 */

/*查询模式*/

#if defined (USE_SPI_POLL)uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];

uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];/*中断模式*/

#elif defined (USE_SPI_INT)uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];

uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];/*DMA模式使用的SRAM4*/

#elif defined (USE_SPI_DMA)

#if defined ( __CC_ARM ) /* IAR *******/__attribute__((section (".RAM_D3"))) uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];

__attribute__((section (".RAM_D3"))) uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];#elif defined (__ICCARM__) /* MDK ********/

#pragma location = ".RAM_D3"uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];#pragma location = ".RAM_D3"uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];#endif

#endif

/**********************************************************************************************************

* 函 数 名: bsp_spiTransfer

* 功能说明: 启动数据传输

* 形 参: 无

* 返 回 值: 无

**********************************************************************************************************/

void bsp_spiTransfer(void)

{if (g_spiLen >SPI_BUFFER_SIZE)

{return;

}/*DMA方式传输*/#ifdef USE_SPI_DMA

wTransferState=TRANSFER_WAIT;if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) !=HAL_OK)

{

Error_Handler(__FILE__, __LINE__);

}while (wTransferState ==TRANSFER_WAIT)

{

;

}#endif

/*中断方式传输*/#ifdef USE_SPI_INT

wTransferState=TRANSFER_WAIT;if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) !=HAL_OK)

{

Error_Handler(__FILE__, __LINE__);

}while (wTransferState ==TRANSFER_WAIT)

{

;

}#endif

/*查询方式传输*/#ifdef USE_SPI_POLLif(HAL_SPI_TransmitReceive(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) !=HAL_OK)

{

Error_Handler(__FILE__, __LINE__);

}#endif}

通过开头宏定义可以方便的切换中断,查询和DMA方式。其中查询和中断方式比较好理解,而DMA方式要特别注意两点:

通过本手册第26章的内存块超方便使用方式,将DMA缓冲定义到SRAM4上。因为本工程是用的DTCM做的主RAM空间,这个空间无法使用通用DMA1和DMA2。

由于程序里面开启了数据Cache,会造成DMA和CPU访问SRAM4数据不一致的问题,特此将SRAM4空间关闭Cache。

/*配置SRAM4的MPU属性为Non-cacheable*/MPU_InitStruct.Enable=MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress= 0x38000000;

MPU_InitStruct.Size=MPU_REGION_SIZE_64KB;

MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable=MPU_ACCESS_NOT_BUFFERABLE;

MPU_InitStruct.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable=MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number=MPU_REGION_NUMBER2;

MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL1;

MPU_InitStruct.SubRegionDisable= 0x00;

MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

75.5.3 第3步:DAC8501的时钟极性和时钟相位配置

首先回忆下STM32H7支持的4种时序配置。

当CPOL = 1, CPHA = 1时

SCK引脚在空闲状态处于低电平,SCK引脚的第2个边沿捕获传输的第1个数据。

当CPOL = 0, CPHA = 1时

SCK引

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值