日志
双SPI总线操作AD7616
2022-04-20 08:21
近期拿到一块EVAL-AD7616SDZ测试板。AD7616SDZ是16bit双通道同步采样的16通道ADC,相比AD7689单通道价格更便宜,速度更高,而且支持双通道同步,是替换AD7689的理想选择。 本来想用STM32MP157A板进行测试的,由于环境搭建以及调试上来说,选一块调试更方便的开发板进行测试,先行探探路。首选了STM32H743ZI_Nucleo板进行测试。 采用双SPI进行操作,那么这个双SPI需要同步时钟。STM32上的SPI2与SPI3同时钟源,SPI4与SPI5同时钟源,所以选择SPI4作为master,SPI5作为slave。 从网上搜到一篇ADI写的《操纵MCU SPI接口 以访问非标准SPI ADC》的文章,采用方案4: 这张图有一点问题,DOUTB应该接MOSI,而不是MISO。 AD7616支持4种操作方式:硬件并口,硬件串口,软件并口,软件串口。其中软件方式是可以配置寄存器的,能够使用AD7616的所有功能,现在选择软件串口方式,那么EVAL-AD7616SDZ测试板需要做以下接线配置: AD7616的初始化顺序: 1> 初始化SPI接口; 2> 初始化CONVST启动转换端口、RESET复位端口、BUSY转换状态端口、CS片选端口; 3> 完全复位AD7616。AD7616有完全复位和部分复位,初始化需要完全复位,RESET低电平状态相当于AD7616断电。 4> 使master SPI的片选信号置低电平; 5> 写配置寄存器。发送0x8414,最高位置1表示写0x2寄存器,写入数据0x14表示32点过采样,此步测试配置; 6> 读取配置寄存器检测配置是否成功,读取的数据应该为0x14; 7> 使master SPI的片选信号置高电平; 8> 启动采样。CONVST产生上升沿启动采样,高电平要至少保持50ns。 9> 检测BUSY信号,出现下降沿表示可以读取采样数据; 10> 使master SPI的片选信号置低电平; 11> SPI4发送0,SPI4读取V0A通道数据; 12> SPI4发送0,SPI5读取V0B通道数据 13> 使master SPI的片选信号置高电平; 重复8~13步可以读取其他通道,当然是在配置了的情况下。默认配置时只能读取V0A和V0B。 最开始使用HAL库的发送与接收函数,发送用HAL_SPI_Transmit,接收用HAL_SPI_Receive。可以读取V0A和V0B通道的采样数据,而且采样数据经过折算后与施加的直流模拟信号一致,说明采样值读取的没问题。但是读取的配置寄存器值为0,通过单步仿真查看写入与读取情况,HAL_SPI_Transmit和HAL_SPI_Receive函数均返回HAL_OK,那么问题出现在哪里呢?此时用示波器观察SCK和MOSI波形,SCK和MISO波形,没有看出问题。后来查出来是HAL_SPI_Transmit函数发送uint16_t数据时将数据分开成两个字节发送,采用数组传入数据,由于ARM是小端,而SPI是MSB传输,数据错位。 调试一天,上面的问题没有找到,用STM32F429板子搭建了一个标准库程序,软件流程完全一样,只是SPI的收发函数用寄存器直接操作,能够正常读取和配置寄存器,正常读取通道采样值。下面把代码公布出来。 ad7616.c部分: #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "bsp.h" #include "adc7616.h" #define CONVST_Pin GPIO_Pin_3 #define CONVST_GPIO_Port GPIOE #define CS_Pin GPIO_Pin_4 #define CS_GPIO_Port GPIOE #define RESET_Pin GPIO_Pin_4 #define RESET_GPIO_Port GPIOA #define BUSY_Pin GPIO_Pin_5 #define BUSY_GPIO_Port GPIOA #define CLR_CNV() GPIO_ResetBits(CONVST_GPIO_Port, CONVST_Pin) #define SET_CNV() GPIO_SetBits(CONVST_GPIO_Port, CONVST_Pin) #define CLR_CS() GPIO_ResetBits(CS_GPIO_Port, CS_Pin) #define SET_CS() GPIO_SetBits(CS_GPIO_Port, CS_Pin) #define CLR_RST() GPIO_ResetBits(RESET_GPIO_Port, RESET_Pin) #define SET_RST() GPIO_SetBits(RESET_GPIO_Port, RESET_Pin) #define BUSY (FlagStatus)GPIO_ReadInputDataBit(BUSY_GPIO_Port, BUSY_Pin) uint16_t ad7616_reg[20]; uint16_t samplearray[16]; uint16_t buffersize = 0; uint8_t busyevent = 0; static int32_t spi_init(ad7616_dev *dev); static int32_t gpio_init(ad7616_dev *dev); int8_t SPI4_SendByte(SPI_TypeDef* SPIx, uint16_t data) {undefined uint8_t res = 0; int32_t retry = 20000; /*!< Wait until the transmit buffer is empty */ while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET) {undefined retry--; if(retry <= 0) return -2; } /*!< Send the data */ SPI_I2S_SendData(SPIx, data); return res; } uint16_t SPI4_ExchangeData(SPI_TypeDef* SPIx, uint16_t data) {undefined int32_t retry = 200; /*!< Wait until the transmit buffer is empty */ while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET) {undefined retry--; if(retry <= 0) return 0; } /*!< Send the byte */ SPI_I2S_SendData(SPIx, data); retry = 200; /*!< Wait to receive a byte*/ while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET) {undefined retry--; if(retry <= 0) return 0; } /* return the byte */ return SPI_I2S_ReceiveData(SPIx); } /** * Read from device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_read(ad7616_dev *dev, uint8_t reg_addr, uint16_t *reg_data) {undefined if (dev->interface == AD7616_SERIAL) {undefined return ad7616_spi_read(dev, reg_addr, reg_data); } else {undefined return ad7616_par_read(dev, reg_addr, reg_data); } } /** * Write to device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_write(ad7616_dev *dev, uint8_t reg_addr, uint16_t reg_data) {undefined if (dev->interface == AD7616_SERIAL) {undefined return ad7616_spi_write(dev, reg_addr, reg_data); } else {undefined return ad7616_par_write(dev, reg_addr, reg_data); } } /** * Read from device using a mask. * @param dev - The device structure. * @param reg_addr - The register address. * @param mask - The mask. * @param data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_read_mask(ad7616_dev *dev, uint8_t reg_addr, uint16_t mask, uint16_t *data) {undefined uint16_t reg_data; int32_t ret; if (dev->interface == AD7616_SERIAL) {undefined ret = ad7616_spi_read(dev, reg_addr, ®_data); } else {undefined ret = ad7616_par_read(dev, reg_addr, ®_data); } *data = (reg_data & mask); return ret; } /** * SPI write to device using a mask. * @param dev - The device structure. * @param reg_addr - The register address. * @param mask - The mask. * @param data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_write_mask(ad7616_dev *dev, uint8_t reg_addr, uint16_t mask, uint16_t data) {undefined uint16_t reg_data; int32_t ret; if (dev->interface == AD7616_SERIAL) {undefined ret = ad7616_spi_read(dev, reg_addr, ®_data); } else {undefined ret = ad7616_par_read(dev, reg_addr, ®_data); } reg_data &= ~mask; reg_data |= data; if (dev->interface == AD7616_SERIAL) {undefined ret |= ad7616_spi_write(dev, reg_addr, reg_data); } else {undefined ret |= ad7616_par_write(dev, reg_addr, reg_data); } return ret; } /** * SPI read from device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_spi_read(ad7616_dev *dev, uint8_t reg_addr, uint16_t *reg_data) {undefined uint16_t regAddr; int32_t ret = 0; regAddr = 0x00 | ((reg_addr & 0x3F) << 1); regAddr = (regAddr<<8) | 0x00; ret = SPI4_ExchangeData(SPI4, regAddr); regAddr = 0x00 | ((reg_addr & 0x3F) << 1); regAddr = (regAddr<<8) | 0x00; ret = SPI4_ExchangeData(SPI4, regAddr); regAddr = (uint16_t)ret; /* return the byte */ *reg_data = regAddr; return ret; } /** * SPI write to device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_spi_write(ad7616_dev *dev, uint8_t reg_addr, uint16_t reg_data) {undefined uint16_t regCfg; int32_t ret=0; regCfg = 0x80 | ((reg_addr & 0x3F) << 1) | ((reg_data & 0x100) >> 8); regCfg = (regCfg<<8) | (reg_data & 0xFF); ret = SPI4_SendByte(SPI4, regCfg); return ret; } /** * PAR read from device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_par_read(ad7616_dev *dev, uint8_t reg_addr, uint16_t *reg_data) {undefined return 0; } /** * PAR write to device. * @param dev - The device structure. * @param reg_addr - The register address. * @param reg_data - The register data. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_par_write(ad7616_dev *dev, uint8_t reg_addr, uint16_t reg_data) {undefined return 0; } void delay(uint32_t us) {undefined int i; for(i=0; i<us; i++) {undefined } } /** * Perform a full reset of the device. * @param dev - The device structure. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_reset(ad7616_dev *dev) {undefined int32_t ret=0; CLR_RST(); /* Low pulse width for a full reset should be at least 1200 ns */ delay_us(2000); SET_RST(); /* 15 ms are required to completely reconfigure the device */ delay_us(20000); return ret; } /** * Set the analog input range for the selected analog input channel. * @param dev - The device structure. * @param ch - The channel number. * Accepted values: AD7616_VA0 * AD7616_VA1 * AD7616_VA2 * AD7616_VA3 * AD7616_VA4 * AD7616_VA5 * AD7616_VA6 * AD7616_VA7 * AD7616_VB0 * AD7616_VB1 * AD7616_VB2 * AD7616_VB3 * AD7616_VB4 * AD7616_VB5 * AD7616_VB6 * AD7616_VB7 * @param range - The analog input range. * Accepted values: AD7616_2V5 * AD7616_5V * AD7616_10V * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_set_range(ad7616_dev *dev, ad7616_ch ch, ad7616_range range) {undefined uint8_t reg_addr; uint8_t mask; uint8_t data; int32_t ret; if (dev->mode == AD7616_SW) {undefined if (ch <= AD7616_VA7) {undefined dev->va[ch] = range; if (ch <= AD7616_VA3) {undefined reg_addr = AD7616_REG_INPUT_RANGE_A1; //0x04 mask = AD7616_INPUT_RANGE(ch, AD7616_10V); //3H || 6H || CH || 18H data = AD7616_INPUT_RANGE(ch, range); //3H || 6H || CH || 18H } else {undefined reg_addr = AD7616_REG_INPUT_RANGE_A2; //0x05 mask = AD7616_INPUT_RANGE(ch - AD7616_VA4, AD7616_10V);//3H || 6H || CH || 18H data = AD7616_INPUT_RANGE(ch - AD7616_VA4, range);//3H || 6H || CH || 18H } } else {undefined dev->vb[ch - AD7616_VB0] = range; if (ch <= AD7616_VB3) {undefined reg_addr = AD7616_REG_INPUT_RANGE_B1; //0x06 mask = AD7616_INPUT_RANGE(ch - AD7616_VB0, AD7616_10V); data = AD7616_INPUT_RANGE(ch - AD7616_VB0, range); } else {undefined reg_addr = AD7616_REG_INPUT_RANGE_B2; //0x07 mask = AD7616_INPUT_RANGE(ch - AD7616_VB4, AD7616_10V); data = AD7616_INPUT_RANGE(ch - AD7616_VB4, range); } } ret = ad7616_write_mask(dev, reg_addr, mask, data); } return ret; } /** * Set the operation mode (software or hardware). * @param dev - The device structure. * @param mode - The operation mode. * Accepted values: AD7616_SW * AD7616_HW * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_set_mode(ad7616_dev *dev, ad7616_mode mode) {undefined uint8_t i; int32_t ret = 0; dev->mode = mode; for (i = 0; i <= AD7616_VA7; i++) {undefined ret |= ad7616_set_range(dev, (ad7616_ch)i, dev->va); ret |= ad7616_set_range(dev, (ad7616_ch)(i + AD7616_VB0), dev->vb); } return ret; } /** * Set the oversampling ratio. * @param dev - The device structure. * @param osr - The oversampling ratio. * Accepted values: AD7616_OSR_0 * AD7616_OSR_2 * AD7616_OSR_4 * AD7616_OSR_8 * AD7616_OSR_16 * AD7616_OSR_32 * AD7616_OSR_64 * AD7616_OSR_128 * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_set_oversampling_ratio(ad7616_dev *dev, ad7616_osr osr) {undefined int32_t ret = 0; if (dev->mode == AD7616_SW) {undefined ret = ad7616_write_mask(dev, AD7616_REG_CONFIG, AD7616_OS(0x7), AD7616_OS(osr)); } return ret; } /** * Start conversion. * @param device - The device structure. * @param init_param - The structure that contains the device initial * parameters. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_startConvst(ad7616_dev *dev) {undefined SET_CNV(); delay_us(5); CLR_CNV(); return 0; } /** * Initialize the device. * @param device - The device structure. * @param init_param - The structure that contains the device initial * parameters. * @return 0 in case of success, negative error code otherwise. */ int32_t ad7616_setup(ad7616_dev *dev) {undefined uint8_t i; int32_t ret = 0; uint16_t databuffer = 0xFFFF; dev->interface = AD7616_SERIAL; dev->mode = AD7616_SW; dev->osr = AD7616_OSR_32; ret |= gpio_init(dev); if (dev->interface == AD7616_SERIAL) {undefined ret |= spi_init(dev); } ad7616_reset(dev); CLR_CS(); for (i = 0; i <= AD7616_VA7; i++) {undefined dev->va = AD7616_10V; dev->vb = AD7616_10V; } ret |= ad7616_spi_read(dev, AD7616_REG_CONFIG, &ad7616_reg[0]); // ret |= ad7616_set_mode(dev, dev->mode); databuffer = 0x8414; ret = SPI4_SendByte(SPI4, databuffer); // ret |= ad7616_set_oversampling_ratio(dev, dev->osr); ret |= ad7616_spi_read(dev, AD7616_REG_CONFIG, &ad7616_reg[2]); ret |= ad7616_spi_read(dev, AD7616_REG_CHANNEL, &ad7616_reg[3]); ret |= ad7616_spi_read(dev, AD7616_REG_INPUT_RANGE_A1, &ad7616_reg[4]); ret |= ad7616_spi_read(dev, AD7616_REG_INPUT_RANGE_A2, &ad7616_reg[5]); ret |= ad7616_spi_read(dev, AD7616_REG_INPUT_RANGE_B1, &ad7616_reg[6]); ret |= ad7616_spi_read(dev, AD7616_REG_INPUT_RANGE_B2, &ad7616_reg[7]); SET_CS(); return ret; } #define CHNL_NBR 2 #define CHNL_IDN 1 uint8_t bufIdx = 0; extern __IO uint32_t uwTimingDelay; uint32_t uwTimingHead; uint32_t uwTimingSample; /***************************************************************************//** * @brief ad7616_capture_serial *******************************************************************************/ int32_t ad7616_capture(ad7616_dev *dev) {undefined int32_t ret = 0; /* wait for conversion finish, BUSY goes from high to low, Polling or interrupt mode */ if(busyevent == 1) {undefined busyevent = 0; uwTimingDelay = 1000; uwTimingHead = uwTimingDelay; /* code number to read per conversion cycle */ while(buffersize < CHNL_NBR) {undefined CLR_CS(); /* Write in the DR register the data to be sent */ *(__IO uint8_t *)&SPI4->DR = 0; /*!< Wait to receive a byte*/ while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET); /* need half SCLK cycle delay for slow SCLK rate < 10MHz */ delay(20); samplearray[bufIdx] = *(__IO uint16_t *)&SPI4->DR; /* Write in the DR register the data to be sent */ *(__IO uint8_t *)&SPI4->DR = 0; /*!< Wait to receive a byte*/ while(SPI_I2S_GetFlagStatus(SPI5, SPI_I2S_FLAG_RXNE) == RESET); samplearray[bufIdx+CHNL_IDN] = *(__IO uint16_t *)&SPI5->DR; SET_CS(); bufIdx++; buffersize += 2; } bufIdx = 0; buffersize = 2; uwTimingSample = uwTimingHead - uwTimingDelay; } else if(buffersize == 0) {undefined ad7616_startConvst(dev); delay(20); } else if(buffersize == 2) {undefined buffersize = 0; LED_Toggle(); delay_us(200000); /* Use Systick to generate microsecond delay */ } return ret; } /***************************************************************************//** * @brief spi_init *******************************************************************************/ static int32_t spi_init(ad7616_dev *dev) {undefined GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; /* Enable SPI bus clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI4, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI5, ENABLE); /* Configure the GPIO clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); /* Configure the GPIO multiplexing function */ GPIO_PinAFConfig(GPIOE, GPIO_PinSource2, GPIO_AF_SPI4); GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_SPI4); GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_SPI4); /*!< SPI pins configuration */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; /* Configure SPI pins: SCK, MISO and MOSI */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_5 | GPIO_Pin_6; GPIO_Init(GPIOE, &GPIO_InitStructure); /* Configure the GPIO multiplexing function */ GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_SPI5); GPIO_PinAFConfig(GPIOF, GPIO_PinSource8, GPIO_AF_SPI5); GPIO_PinAFConfig(GPIOF, GPIO_PinSource7, GPIO_AF_SPI5); GPIO_PinAFConfig(GPIOF, GPIO_PinSource6, GPIO_AF_SPI5); /* Configure SPI pins: SCK, MISO and MOSI */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9; GPIO_Init(GPIOF, &GPIO_InitStructure); /* Set SPI interface */ SPI_I2S_DeInit(SPI5); SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly; SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; /* 1Mbit/s */ SPI_InitStructure.SPI_CRCPolynomial = 0; SPI_Init(SPI5, &SPI_InitStructure); /* Fills each SPI_InitStruct member with its default value */ SPI_I2S_DeInit(SPI4); /* Set SPI interface */ SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; /* 1Mbit/s */ SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI4, &SPI_InitStructure); SPI_Cmd(SPI4, ENABLE); SPI_Cmd(SPI5, ENABLE); return 0; } /***************************************************************************//** * @brief gpio_init *******************************************************************************/ static int32_t gpio_init(ad7616_dev *dev) {undefined GPIO_InitTypeDef GPIO_InitStruct; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; /* Configure the GPIO clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /*Configure GPIO pin : CS_Pin */ GPIO_InitStruct.GPIO_Pin = CS_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(CS_GPIO_Port, &GPIO_InitStruct); GPIO_SetBits(CS_GPIO_Port, CS_Pin); /*Configure GPIO pin : CONVST_Pin */ GPIO_InitStruct.GPIO_Pin = CONVST_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(CONVST_GPIO_Port, &GPIO_InitStruct); GPIO_ResetBits(CONVST_GPIO_Port, CONVST_Pin); /*Configure GPIO pin : RESET_Pin */ GPIO_InitStruct.GPIO_Pin = RESET_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(RESET_GPIO_Port, &GPIO_InitStruct); GPIO_ResetBits(RESET_GPIO_Port, RESET_Pin); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /*Configure GPIO pin : BUSY_Pin */ GPIO_InitStruct.GPIO_Pin = BUSY_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(BUSY_GPIO_Port, &GPIO_InitStruct); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource5); EXTI_InitStructure.EXTI_Line = EXTI_Line5; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); return 0; } /***************************************************************************//** * @brief gpio_init *******************************************************************************/ void EXTI9_5_IRQHandler(void) {undefined if(EXTI_GetITStatus(EXTI_Line5) != RESET) {undefined EXTI_ClearITPendingBit(EXTI_Line5); busyevent = 1; } } 初始化调用ad7616_setup函数,在主函数中调用ad7616_capture函数,不需要加延时。后面应用到项目中可以建个定时器,定时启动采样。经测试,同步的两个通道采样时间,在SPI时钟8分频时一对通道采样读取2微秒,16分频时3微秒,32分频时6微秒,还是很快的,SPI采用2分频是不行的。所以需要更高采样的,需要使用并口操作,如FMC。 下面把头文件贴上。 ad7616.h部分与官方库一致。 #ifndef AD7616_H_ #define AD7616_H_ #include "stm32f4xx_conf.h" /******************************************************************************/ /********************** Macros and Constants Definitions **********************/ /******************************************************************************/ #define AD7616_REG_CONFIG 0x02 #define AD7616_REG_CHANNEL 0x03 #define AD7616_REG_INPUT_RANGE_A1 0x04 #define AD7616_REG_INPUT_RANGE_A2 0x05 #define AD7616_REG_INPUT_RANGE_B1 0x06 #define AD7616_REG_INPUT_RANGE_B2 0x07 #define AD7616_REG_SEQUENCER_STACK(x) (0x20 + (x)) /* AD7616_REG_CONFIG */ #define AD7616_SDEF (1 << 7) #define AD7616_BURSTEN (1 << 6) #define AD7616_SEQEN (1 << 5) #define AD7616_OS(x) (((x) & 0x7) << 2) #define AD7616_STATUSEN (1 << 1) #define AD7616_CRCEN (1 << 0) /* AD7616_REG_INPUT_RANGE */ #define AD7616_INPUT_RANGE(ch, x) (((x) & 0x3) << (((ch) & 0x3) * 2)) /* AD7616_REG_SEQUENCER_STACK(x) */ #define AD7616_ADDR(x) (((x) & 0x7F) << 9) #define AD7616_SSREN (1 << 8) #define AD7616_BSEL(x) (((x) & 0xF) << 4) #define AD7616_ASEL(x) (((x) & 0xF) << 0) /* AD7616_REG_STATUS */ #define AD7616_STATUS_A(x) (((x) & 0xF) << 12) #define AD7616_STATUS_B(x) (((x) & 0xF) << 8) #define AD7616_STATUS_CRC(x) (((x) & 0xFF) << 0) /******************************************************************************/ /*************************** Types Declarations *******************************/ /******************************************************************************/ typedef enum {undefined AD7616_SW, /* 软件模式 */ AD7616_HW, /* 硬件模式 */ } ad7616_mode; typedef enum {undefined AD7616_SERIAL, /* 串行接口 */ AD7616_PARALLEL, /* 并行接口 */ } ad7616_interface; typedef enum {undefined AD7616_VA0, AD7616_VA1, AD7616_VA2, AD7616_VA3, AD7616_VA4, AD7616_VA5, AD7616_VA6, AD7616_VA7, AD7616_VB0, AD7616_VB1, AD7616_VB2, AD7616_VB3, AD7616_VB4, AD7616_VB5, AD7616_VB6, AD7616_VB7, } ad7616_ch; typedef enum {undefined AD7616_2V5 = 1, /* 采样范围 */ AD7616_5V = 2, AD7616_10V = 3, } ad7616_range; typedef enum {undefined AD7616_OSR_0, /* 过采样点数 */ AD7616_OSR_2, AD7616_OSR_4, AD7616_OSR_8, AD7616_OSR_16, AD7616_OSR_32, AD7616_OSR_64, AD7616_OSR_128, } ad7616_osr; typedef struct {undefined /* Device Settings */ ad7616_interface interface; ad7616_mode mode; ad7616_range va[8]; ad7616_range vb[8]; ad7616_osr osr; } ad7616_dev; /******************************************************************************/ /************************ Functions Declarations ******************************/ /******************************************************************************/ /* SPI read from device. */ int32_t ad7616_read(ad7616_dev *dev, uint8_t reg_addr, uint16_t *reg_data); /* SPI write to device. */ int32_t ad7616_write(ad7616_dev *dev, uint8_t reg_addr, uint16_t reg_data); /* SPI read from device using a mask. */ int32_t ad7616_read_mask(ad7616_dev *dev, uint8_t reg_addr, uint16_t mask, uint16_t *data); /* SPI write to device using a mask. */ int32_t ad7616_write_mask(ad7616_dev *dev, uint8_t reg_addr, uint16_t mask, uint16_t data); /* SPI read from device. */ int32_t ad7616_spi_read(ad7616_dev *dev, uint8_t reg_addr, uint16_t *reg_data); /* SPI write to device. */ int32_t ad7616_spi_write(ad7616_dev *dev, uint8_t reg_addr, uint16_t reg_data); /* PAR read from device. */ int32_t ad7616_par_read(ad7616_dev *dev, uint8_t reg_addr, uint16_t *reg_data); /* PAR write to device. */ int32_t ad7616_par_write(ad7616_dev *dev, uint8_t reg_addr, uint16_t reg_data); /* Perform a full reset of the device. */ int32_t ad7616_reset(ad7616_dev *dev); /* Set the analog input range for the selected analog input channel. */ int32_t ad7616_set_range(ad7616_dev *dev, ad7616_ch ch, ad7616_range range); /* Set the operation mode (software or hardware). */ int32_t ad7616_set_mode(ad7616_dev *dev, ad7616_mode mode); /* Set the oversampling ratio. */ int32_t ad7616_set_oversampling_ratio(ad7616_dev *dev, ad7616_osr osr); /* Initialize the device. */ int32_t ad7616_setup(ad7616_dev *dev); int32_t ad7616_capture(ad7616_dev *dev); ———————————————— 版权声明:本文为CSDN博主「信阳茶农」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/kwx618/article/details/107643572 |
下一篇: 下班了,太累了
上一篇: TVS与稳压二极管区别