STM32F4硬件IIC+DMA使用

1.STM32硬件IIC一直被大家说存在问题,实际测试发现确实是有这种情况,借助网上很多人的经验,终于把硬件IIC写完了。

2.使用DMA时,发现发送数据(写寄存器)时序和实际不符,比如发送4字节数据时,如果DMA缓冲区单字节长度配置为4,则实际时序发现只有三个,需要将DMA缓冲区单字节长度配置为5,才可以正常使用

3.当然,如果使用STM32的HAL库,这些问题其实都可以避免,因为底层ST已经做了超时及错误的处理。

4.使用的IIC为自定义的格式,

写寄存器操作为:

START+ACK(从机的ACK信号)+IIC设备地址+(从机的ACK信号)+START+ACK(从机的ACK信号)+IIC写寄存器地址+ACK(从机的ACK信号)+IIC写数据(4Byte,每个数据后都有ACK)+STOP

读寄存器操作为:

START+ACK(从机的ACK信号)+IIC设备地址+(从机的ACK信号)+START+ACK(从机的ACK信号)+IIC读寄存器地址+ACK(从机的ACK信号)+IIC读数据(4Byte,前n个数据后都有(主机发送的)ACK,最后1byte数据后如果发ACK,表示还有数据要读,如果最后1byte数据后为NACK,后面紧接着就是停止位)+STOP

硬件IIC使用DMA还是不使用DMA,通过宏定义选择,代码如下:

#ifndef _hardiic_h
#define _hardiic_h

#ifdef __cplusplus
	extern "C"{
#endif		

#include "sys.h"




#define AT24Cxx_PageSize   8  //存储器块大小
#define I2C_TIME		       ((u32)65535)
    
#define DMA_USER            1  
    
#define HARD_IIC_USER       0  //是否使用硬件IIC而不使用DMA,现在不使用DMA正常,使用DMA连续读还是有问题
#define IIC_DMA_BUFF_LEN    4  
#define IIC_READ_DATA_REG_LEN   16
#define IIC_REV_BUFF_LEN    IIC_READ_DATA_REG_LEN
  
/**********全局宏定义,结构体,枚举等***********/
extern u8 IIC_DmaRevBuff[IIC_REV_BUFF_LEN];
extern u8 IIC_RevBuff[IIC_REV_BUFF_LEN];
extern u8 IIC_SendBuff[IIC_REV_BUFF_LEN];  
extern u8 g_ackFlag; 
extern u8 g_ackErrorFlag; 
    

void Hard_IIC_Init(u8 SlaveAdd);
void IIC_DmaInit(u8 SlaveAdd);    
void IIC_TxDmaConfig(u8 *pbuff, u8 len);
void IIC_RxDmaConfig(u8 *pbuff, u16 len, u8 it_mode); 

void I2C_DMA_Read(u8 SlaveAddr,u8 ReadAddr, u8 *err);
u32 I2C_DMA_ReadReg(u8 ReadAddr, u8 *err);

void I2C_DMA_ReadDataAddrReg(void);

void I2C_DMA_Write(u8 SlaveAddr, u8 WriteAddr,u32 DataToWrite, u8 *err);
void I2C_DMA_WriteReg(u8 WriteAddr,u32 DataToWrite, u8 *err);

void Hard_IICWaiteStandby(uint8_t SlaveAdd);

void IIC_DataRegToUart(void);

//void IIC_HardWriteOneWord(u8 SlaveAdd, u8 WriteAdd, u32 write_data, u8 * err);
//u32 IIC_HardReadOneWord(uint8_t SlaveAdd, u8 ReadAdd, u8 * err);
//void IIC_HardReadNWord(void);
/**
  ****************************** Support C++ **********************************
**/
#ifdef __cplusplus
	}
#endif
/**
  *****************************************************************************
**/


#endif  /* end hardiic.h */
#include "hardiic.h"
#include "iic_link.h"
#include "uart_cmd_handle.h"
#include "delay.h"
#include "uartfifo.h"
//#include "DMA.h"

u8 IIC_DmaRevBuff[IIC_REV_BUFF_LEN] = {0x00}; 
u8 IIC_RevBuff[IIC_REV_BUFF_LEN]  = {0x00};
u8 IIC_SendBuff[IIC_REV_BUFF_LEN] = {0x00};  
u8 g_ackFlag = 0; 
u8 g_ackErrorFlag = 0; 
u8 g_continuFlag = 0;
u8 g_readDataEvent = 0;

//硬件IIC初始化 
void Hard_IIC_Init(u8 SlaveAdd)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	I2C_InitTypeDef I2C_InitStructure;
	I2C_DeInit(I2C1);	
  
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	//管脚复用
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

	//配置IIC参数
	I2C_InitStructure.I2C_Mode                = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle           = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1         = SlaveAdd;  //从设备地址
	I2C_InitStructure.I2C_Ack                 = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed          = 400000;  //SCL最大400KHz
	
	I2C_Cmd(I2C1, ENABLE);
//  I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_ERR , ENABLE);
	I2C_Init(I2C1, &I2C_InitStructure);
	I2C_AcknowledgeConfig(I2C1, ENABLE); 
  
	//禁止时钟延长
	I2C1->CR1 |= 0x80;
//	//允许时钟延长
//	I2C1->CR1 &= 0x7F;
}

硬件IIC DMA初始化
void IIC_DmaInit(u8 SlaveAdd)
{
	NVIC_InitTypeDef NVIC_InitStruct;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
  Hard_IIC_Init(SlaveAdd);

	NVIC_InitStruct.NVIC_IRQChannel                   = DMA1_Stream0_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
  
	NVIC_InitStruct.NVIC_IRQChannel                   = DMA1_Stream6_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE;
	NVIC_Init(&NVIC_InitStruct);

//	DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_FEIF6 | DMA_FLAG_DMEIF6 | DMA_FLAG_TEIF6 |
//															DMA_FLAG_HTIF6 | DMA_FLAG_TCIF6);                              
//	DMA_Cmd(DMA1_Stream6, DISABLE);
//	DMA_DeInit(DMA1_Stream6);      
//	IIC_TxDmaConfig(IIC_SendBuff, IIC_BUFF_LEN); //IIC TX DMA初始化

//	DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_FEIF0 | DMA_FLAG_DMEIF0 | DMA_FLAG_TEIF0 |
//															DMA_FLAG_HTIF0 | DMA_FLAG_TCIF0);
//	DMA_Cmd(DMA1_Stream0, DISABLE);
//	DMA_DeInit(DMA1_Stream0);
//	IIC_RxDmaConfig(IIC_RevBuff, IIC_BUFF_LEN); //IIC RX DMA初始化

//	DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE);
//	DMA_ITConfig(DMA1_Stream0, DMA_IT_TC, ENABLE);
  
//	I2C_DMACmd(I2C1, ENABLE);
}

void Hard_IICWaiteStandby(uint8_t SlaveAdd)
{
	u16 tmp = 0;
	
	I2C1->SR1 &= 0x0000;  //清除状态寄存器1
	
	do
	{
		I2C_GenerateSTART(I2C1, ENABLE);  //产生起始信号
		tmp = I2C1->SR1;  //读取SR1寄存器,然后写入数据寄存器操作来清除SB位,EV5
		I2C_Send7bitAddress(I2C1, SlaveAdd, I2C_Direction_Transmitter);  //发送从设备地址
	} while ((I2C1->SR1 & 0x0002) == 0x0000);  //当ADDR = 1时,表明应答了,跳出循环
	I2C_ClearFlag(I2C1, I2C_FLAG_AF);  //清除应答失败标志位
	I2C_GenerateSTOP(I2C1, ENABLE);  //发送停止信号
}

#if HARD_IIC_USER

//写一个寄存器
void I2C_DMA_WriteReg(u8 WriteAdd, u32 write_data, u8 * err)
{
	u16 sta = 0;
	u16 temp = 0;
  u8 NumToWrite = 4;
  u8 write_value = 0;
	
	while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))  //等待IIC
	{
		temp++;
		if (temp > 800)
		{
			*err |= 1<<0;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	I2C_GenerateSTART(I2C1, ENABLE);  //产生起始信号
	temp = 0;
	//EV5
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
		temp++;
		if (temp > 800)
		{
			*err |= 1<<1;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	I2C_Send7bitAddress(I2C1, IIC_LINK_ADDR, I2C_Direction_Transmitter);  //发送设备地址
	temp = 0;
	//EV6
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{
		temp++;
		if (temp > 1000)
		{
			*err |= 1<<2;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	//读取SR2状态寄存器
	sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
	I2C_SendData(I2C1, WriteAdd);  //发送存储地址
	temp = 0;
	//EV8
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
	{
		temp++;
		if (temp > 800)
		{
			*err |= 1<<3;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
  
  I2C_GenerateSTART(I2C1, ENABLE);  //产生起始信号
	temp = 0;
	//EV5
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
		temp++;
		if (temp > 800)
		{
			*err |= 1<<1;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	I2C_Send7bitAddress(I2C1, IIC_LINK_ADDR, I2C_Direction_Transmitter);  //发送设备地址
	temp = 0;
	//EV6
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{
		temp++;
		if (temp > 1000)
		{
			*err |= 1<<2;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	//读取SR2状态寄存器
	sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!

	//循环发送数据
	while (NumToWrite)
	{
    NumToWrite--;
    write_value = (u8)(write_data>>(NumToWrite*8));
		I2C_SendData(I2C1, write_value);  //发送数据
		temp = 0;
		//EV8_2
		while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
		{
			temp++;
			if (temp > 800)
			{
				*err |= 1<<4;
				I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
				return;
			}
		}
	}
	I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
  Hard_IICWaiteStandby(IIC_LINK_ADDR);  //等待完成操作
}


u32 I2C_DMA_ReadReg(u8 ReadAdd, u8 * err)
{
	u16 i = 0;
	u16 sta = 0;
  u8 NumToRead = 4;
  u8 pbuff[4] = {0x00};
  u32 ret = 0;
	
	while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))  //等待IIC
	{
		i++;
		if (i > 800)
		{
			*err |= 1<<0;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return 0;
		}
	}
	I2C_GenerateSTART(I2C1, ENABLE);  //发送起始信号
	i = 0;
	//EV5
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
		i++;
		if (i > 800)
		{
			*err |= 1<<1;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return 0;
		}
	}
	I2C_Send7bitAddress(I2C1, IIC_LINK_ADDR, I2C_Direction_Transmitter);  //发送设备地址
	i = 0;
	//EV6
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{
		i++;
		if (i > 800)
		{
			*err |= 1<<2;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return 0;
		}
	}
	sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
	I2C_SendData(I2C1, ReadAdd);  //发送存储地址
	i = 0;
	//EV8
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
	{
		i++;
		if (i > 2000)
		{
			*err |= 1<<3;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return 0;
		}
	}
	I2C_GenerateSTART(I2C1, ENABLE);  //重启信号
	i = 0;
	//EV5
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
		i++;
		if (i > 800)
		{
			*err |= 1<<4;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return 0;
		}
	}
	I2C_Send7bitAddress(I2C1, IIC_LINK_ADDR, I2C_Direction_Receiver);  //读取命令
	i = 0;
	//EV6
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
	{
		i++;
		if (i > 800)
		{
			*err |= 1<<5;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return 0;
		}
	}
	sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!

	//批量接收数据
	while (NumToRead)
	{
		if (NumToRead == 1)  //最后一个数据了,不发送应答信号
		{
			I2C_AcknowledgeConfig(I2C1, DISABLE);  //发送NACK
			I2C_GenerateSTOP(I2C1, ENABLE);
		}
    //判断RxNE是否为1,EV7
		if (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
		{
      NumToRead--;
			pbuff[3-NumToRead] = I2C_ReceiveData(I2C1);
		}
	}
	I2C_AcknowledgeConfig(I2C1, ENABLE);
  ret = (pbuff[0]<<24) + (pbuff[1]<<16) + (pbuff[2]<<8) + pbuff[3];  
	return ret;
}

void I2C_DMA_ReadDataAddrReg(void)
{
	u16 i = 0;
  u8 sta;
  u8 NumToRead = 4;
  u8 pbuffer[IIC_READ_DATA_REG_LEN] = {0x00};
  u8 error = 0;
  
	Hard_IIC_Init(IIC_LINK_ADDR0);
  
	while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))  //等待IIC
	{
		i++;
		if (i > 800)
		{
			error |= 1<<0;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	I2C_GenerateSTART(I2C1, ENABLE);  //发送起始信号
	i = 0;
	//EV5
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
		i++;
		if (i > 800)
		{
			error |= 1<<1;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	I2C_Send7bitAddress(I2C1, IIC_LINK_ADDR, I2C_Direction_Transmitter);  //发送设备地址
	i = 0;
	//EV6
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
	{
		i++;
		if (i > 800)
		{
			error |= 1<<2;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
	I2C_SendData(I2C1, 0xff);  //发送存储地址
	i = 0;
	//EV8
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
	{
		i++;
		if (i > 2000)
		{
			error |= 1<<3;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	I2C_GenerateSTART(I2C1, ENABLE);  //重启信号
	i = 0;
	//EV5
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
		i++;
		if (i > 800)
		{
			error |= 1<<4;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	I2C_Send7bitAddress(I2C1, IIC_LINK_ADDR, I2C_Direction_Receiver);  //读取命令
	i = 0;
	//EV6
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
	{
		i++;
		if (i > 800)
		{
			error |= 1<<5;
			I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
		}
	}
	sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
 
//    DealDataFromUart1();
    error = 0;
    i=0;
    
    NumToRead = IIC_READ_DATA_REG_LEN;
    //批量接收数据
    while (NumToRead)
    {
      if(NumToRead == 1)  //最后一个数据了,不发送应答信号
      {
        I2C_AcknowledgeConfig(I2C1, DISABLE);  //发送NACK
        I2C_GenerateSTOP(I2C1, ENABLE);
      }
      //判断RxNE是否为1,EV7
      if (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
      {
        NumToRead--;
        pbuffer[i++] = I2C_ReceiveData(I2C1);
      }

    }
    
  for(i=0;i<IIC_READ_DATA_REG_LEN;i++) //数据放入缓冲区
  {
    IICinfifo_DataIn(pbuffer[i]);
  }
  IICinfifo_DataIn(error);
  g_readDataEvent = 1;
  
  I2C_AcknowledgeConfig(I2C1, ENABLE);  
}

#else

void IIC_TxDmaConfig(u8 *pbuff, u8 len)
{
  DMA_InitTypeDef DMA_InitStruct;
//  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
//  IIC_DmaInit(IIC_LINK_ADDR0);

  DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_FEIF6 | DMA_FLAG_DMEIF6 | DMA_FLAG_TEIF6 |
															DMA_FLAG_HTIF6 | DMA_FLAG_TCIF6);                              
	DMA_Cmd(DMA1_Stream6, DISABLE);
//	DMA_DeInit(DMA1_Stream6); 
  while (DMA_GetCmdStatus(DMA1_Stream6) != DISABLE);
  
  DMA_InitStruct.DMA_Channel            = DMA_Channel_1;
	DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)&I2C1->DR;   
	DMA_InitStruct.DMA_Memory0BaseAddr    = (u32)&pbuff[0];
	DMA_InitStruct.DMA_DIR                = DMA_DIR_MemoryToPeripheral;
	DMA_InitStruct.DMA_BufferSize         = len+1;//IIC_BUFF_LEN;
	DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
	DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
	DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;
	DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;
	DMA_InitStruct.DMA_FIFOMode           = DMA_FIFOMode_Disable;
	DMA_InitStruct.DMA_FIFOThreshold      = DMA_FIFOThreshold_Full;
	DMA_InitStruct.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
	DMA_InitStruct.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
	DMA_Init(DMA1_Stream6, &DMA_InitStruct); 
  
  DMA_ITConfig(DMA1_Stream6, DMA_IT_TC|DMA_IT_TE, ENABLE);
  I2C_DMACmd(I2C1, ENABLE);
  
  while (DMA_GetCmdStatus(DMA1_Stream6) != DISABLE);
  DMA_Cmd(DMA1_Stream6, ENABLE);
}

void IIC_RxDmaConfig(u8 *pbuff, u16 len, u8 it_mode)
{
  DMA_InitTypeDef DMA_InitStruct;
//  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
//  IIC_DmaInit(IIC_LINK_ADDR0);
  
  DMA_Cmd(DMA1_Stream0, DISABLE);
  while (DMA_GetCmdStatus(DMA1_Stream0) != DISABLE);
//	DMA_DeInit(DMA1_Stream0); 
  
  DMA_InitStruct.DMA_Channel            = DMA_Channel_1;
	DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)&I2C1->DR;   
	DMA_InitStruct.DMA_Memory0BaseAddr    = (u32)&pbuff[0];
	DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralToMemory;
	DMA_InitStruct.DMA_BufferSize         = len;//IIC_BUFF_LEN;
	DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
	DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
	DMA_InitStruct.DMA_Mode               = DMA_Mode_Normal;
	DMA_InitStruct.DMA_Priority           = DMA_Priority_VeryHigh;
	DMA_InitStruct.DMA_FIFOMode           = DMA_FIFOMode_Disable;
	DMA_InitStruct.DMA_FIFOThreshold      = DMA_FIFOThreshold_Full;
	DMA_InitStruct.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
	DMA_InitStruct.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
	DMA_Init(DMA1_Stream0, &DMA_InitStruct); 

  DMA_ITConfig(DMA1_Stream0, DMA_IT_TC|DMA_IT_TE, ENABLE);
  
  I2C_DMACmd(I2C1, ENABLE);
  
  while (DMA_GetCmdStatus(DMA1_Stream0) != DISABLE);
  I2C_DMALastTransferCmd(I2C1, ENABLE);

  DMA_Cmd(DMA1_Stream0, ENABLE);
}

vu32 I2C_TimeCnt = I2C_TIME;

void I2C_DMA_Read(u8 SlaveAddr,u8 ReadAddr, u8 *err)
{
  u16 sta = 0;
 
  *err = 0;
  g_ackErrorFlag = 0;
  g_ackFlag = 0;
  g_continuFlag = 0; 
  
  IIC_DmaInit(IIC_LINK_ADDR0);
  
	I2C_TimeCnt = I2C_TIME;
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<0);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return ;
    }  
  }
  I2C_GenerateSTART(I2C1, ENABLE);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<1);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    }      
  }
  
	I2C_Send7bitAddress(I2C1, SlaveAddr, I2C_Direction_Transmitter);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //I2C_EVENT_MASTER_BYTE_TRANSMITTING
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<2);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    } 
  }
  sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
  I2C_SendData(I2C1, ReadAddr);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<3);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    } 
  }
  
	I2C_GenerateSTART(I2C1, ENABLE);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<4);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    }  
  }
	I2C_Send7bitAddress(I2C1, SlaveAddr, I2C_Direction_Receiver);

  I2C_TimeCnt = I2C_TIME;
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<5);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    }  
  }
  sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
  IIC_RxDmaConfig(IIC_DmaRevBuff, IIC_DMA_BUFF_LEN, 0); //IIC RX DMA初始化
}

u32 I2C_DMA_ReadReg(u8 ReadAddr, u8 *err)
{
  u32 temp = 0;
  
	I2C_DMA_Read(IIC_LINK_WRITE_MODE, ReadAddr, err);

	I2C_TimeCnt = I2C_TIME;
  while(g_ackFlag==0)
  {
    if((I2C_TimeCnt--) == 0) 
    {
      *err |= (0x01<<6);
      break;
    }
  }
  *err |= (g_ackErrorFlag<<7);
  temp = (IIC_DmaRevBuff[0]<<24) + (IIC_DmaRevBuff[1]<<16) + (IIC_DmaRevBuff[2]<<8) + IIC_DmaRevBuff[3];  
	return temp;
}

//连续读数据
void I2C_DMA_ReadDataAddrReg(void)
{
  u16 sta = 0;

  g_ackErrorFlag = 0;
  g_ackFlag = 0;
  
  IIC_DmaInit(IIC_LINK_ADDR0);
  
	I2C_TimeCnt = I2C_TIME;
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
  {
    if((I2C_TimeCnt--) == 0)
    {
      g_ackErrorFlag |= (0x01<<0);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return ;
    }  
  }
  I2C_GenerateSTART(I2C1, ENABLE);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
    if((I2C_TimeCnt--) == 0)
    {
      g_ackErrorFlag |= (0x01<<1);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    }      
  }
  
	I2C_Send7bitAddress(I2C1, IIC_LINK_WRITE_MODE, I2C_Direction_Transmitter);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //I2C_EVENT_MASTER_BYTE_TRANSMITTING
  {
    if((I2C_TimeCnt--) == 0)
    {
      g_ackErrorFlag |= (0x01<<2);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    } 
  }
  sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
  I2C_SendData(I2C1, 0xff);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
  {
    if((I2C_TimeCnt--) == 0)
    {
      g_ackErrorFlag |= (0x01<<3);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    } 
  }
  
	I2C_GenerateSTART(I2C1, ENABLE);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if((I2C_TimeCnt--) == 0)
    {
      g_ackErrorFlag |= (0x01<<4);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    }  
  }
	I2C_Send7bitAddress(I2C1, IIC_LINK_WRITE_MODE, I2C_Direction_Receiver);

  I2C_TimeCnt = I2C_TIME;
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
  {
    if((I2C_TimeCnt--) == 0)
    {
      g_ackErrorFlag |= (0x01<<5);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
      return ;
    }  
  }

  sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
  g_continuFlag = 1;  //连续读取标志
  g_readDataEvent = 0;
  IIC_RxDmaConfig(IIC_DmaRevBuff, IIC_READ_DATA_REG_LEN,0); //IIC RX DMA初始化 
  
  I2C_TimeCnt = I2C_TIME;
  while(g_ackFlag==0)
  {
    if((I2C_TimeCnt--) == 0) 
    {
      break;
    }
  }
//  delay_ms(10);
   
//      goto HARD_IIC_LOOP2;
//        DMA_Cmd(DMA1_Stream0, DISABLE);                      //关闭DMA传输 
//        while (DMA_GetCmdStatus(DMA1_Stream0) != DISABLE){}	//确保DMA可以被设置  
//        DMA_MemoryTargetConfig(DMA1_Stream0, (u32)&IIC_RevBuff[0], DMA_Memory_0);
//        DMA_SetCurrDataCounter(DMA1_Stream0, IIC_DMA_BUFF_LEN-1);          //数据传输量  
//        DMA_Cmd(DMA1_Stream0, ENABLE);                      //开启DMA传输     

}

void I2C_DMA_Write(u8 SlaveAddr, u8 WriteAddr,u32 DataToWrite, u8 *err)
{
  u16 sta;
  *err = 0;
  g_ackErrorFlag = 0;
  g_ackFlag = 0;
 
  IIC_DmaInit(IIC_LINK_ADDR0);
  
	I2C_TimeCnt = I2C_TIME;
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<0);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
      
    }   
  }
  
	I2C_GenerateSTART(I2C1, ENABLE);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
	{
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<1);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
    }      
  }
  
	I2C_Send7bitAddress(I2C1, SlaveAddr, I2C_Direction_Transmitter);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //I2C_EVENT_MASTER_BYTE_TRANSMITTING
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<2);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
    } 
  }
  sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
  I2C_SendData(I2C1, WriteAddr);
	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<3);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
    } 
  }
  I2C_GenerateSTART(I2C1, ENABLE);

	I2C_TimeCnt = I2C_TIME;
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<4);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
    }  
  }
	I2C_Send7bitAddress(I2C1, SlaveAddr, I2C_Direction_Transmitter);
  sta = I2C1->SR2;  //软件读取SR1寄存器后,对SR2寄存器的读操作将清除ADDR位,不可少!!!!!!!!!
  I2C_TimeCnt = I2C_TIME;
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if((I2C_TimeCnt--) == 0)
    {
      *err |= (0x01<<5);
      I2C_GenerateSTOP(I2C1, ENABLE);  //产生停止信号
			return;
    }  
  }
  
  IIC_SendBuff[0] = (DataToWrite>>24)&0xff;
  IIC_SendBuff[1] = (DataToWrite>>16)&0xff;
  IIC_SendBuff[2] = (DataToWrite>>8)&0xff;
  IIC_SendBuff[3] = (DataToWrite>>0)&0xff;
	IIC_TxDmaConfig(IIC_SendBuff, IIC_DMA_BUFF_LEN); //IIC TX DMA初始化
}


void I2C_DMA_WriteReg(u8 WriteAddr,u32 DataToWrite, u8 *err)
{
	I2C_DMA_Write(IIC_LINK_WRITE_MODE, WriteAddr, DataToWrite, err);
  I2C_TimeCnt = I2C_TIME;
  while(g_ackFlag==0)
  {
    if((I2C_TimeCnt--) == 0) 
    {
      *err |= (0x01<<4);
      break;
    }
  }
  *err |= (g_ackErrorFlag<<5);
//  Hard_IICWaiteStandby(IIC_LINK_ADDR);  //等待完成操作
	return;
}


void DMA1_Stream6_IRQHandler( void )
{
	if(DMA_GetFlagStatus(DMA1_Stream6, DMA_FLAG_TCIF6) != RESET)  //传输完成中断
  {
		DMA_Cmd(DMA1_Stream6, DISABLE);
		DMA_ClearFlag(DMA1_Stream6, DMA_FLAG_TCIF6);

		I2C_TimeCnt = I2C_TIME;
		while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF))
    {
      if((I2C_TimeCnt--) == 0) 
      {
        g_ackErrorFlag = 1;
      }
      break;
    }
    
		I2C_GenerateSTOP(I2C1, ENABLE);
    g_ackErrorFlag = 0;
    g_ackFlag = 1;
	}
  else if(DMA_GetITStatus(DMA1_Stream6,DMA_IT_TEIF6) != RESET) //传输失败中断
  {
    DMA_Cmd(DMA1_Stream6, DISABLE);
    DMA_ClearITPendingBit(DMA1_Stream6,DMA_IT_TEIF6);
    I2C_GenerateSTOP(I2C1, ENABLE);
    g_ackErrorFlag = 1;
    g_ackFlag = 1;
  }

}

void DMA1_Stream0_IRQHandler( void )
{
  u8 i=0;
	if(DMA_GetFlagStatus(DMA1_Stream0, DMA_FLAG_TCIF0) != RESET) 
  {
    DMA_Cmd(DMA1_Stream0, DISABLE);
    DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_TCIF0);
    I2C_GenerateSTOP(I2C1, ENABLE);
    if(g_continuFlag == 1) //连续读数据
    {
      for(i=0; i<IIC_READ_DATA_REG_LEN; i++)
      {
        IICinfifo_DataIn(IIC_DmaRevBuff[i]);
        IIC_DmaRevBuff[i] = 0;
      }  
      IICinfifo_DataIn(g_ackErrorFlag);
    }

    g_ackErrorFlag = 0;
    g_ackFlag = 1; 
    g_readDataEvent = 1;
    
	}
//  else if(DMA_GetITStatus(DMA1_Stream0,DMA_IT_HTIF0) != RESET)  //半传输完成中断
//  {
//    DMA_Cmd(DMA1_Stream0, DISABLE);
//    DMA_ClearITPendingBit(DMA1_Stream0,DMA_IT_HTIF0);	
//    g_ackErrorFlag = 0;
//    g_ackFlag = 1;
//  }
  else if(DMA_GetITStatus(DMA1_Stream0,DMA_IT_TEIF0) != RESET) //传输失败中断
  {
    DMA_Cmd(DMA1_Stream0, DISABLE);
    DMA_ClearITPendingBit(DMA1_Stream0,DMA_IT_TEIF0);
    I2C_GenerateSTOP(I2C1, ENABLE);
    g_ackErrorFlag = 1;
    g_ackFlag = 1;
  }

}

#endif

void IIC_DataRegToUart(void)
{
  u8 i, j;
  u8 pbuffer[IIC_READ_DATA_REG_LEN+10] = {0x00};

  while(g_readDataEvent!=1){}
  
    while(IICinfifo_HaveData() != 0)
    {
      i=0;
      pbuffer[i++] = 0x30;
      pbuffer[i++] = 0xff;   
      for(j=0;j<(IIC_READ_DATA_REG_LEN+1);j++)
      {
        pbuffer[i++] = IICinfifo_DataOut();
      }  
      UART1_SendCmdData(pbuffer, i);  
      delay_ms(10);
    }  
  
}

int main(void)
{
  u8 error=0;
  u32 jiCunQi_data = 0;
  
  IIC_DmaInit(IIC_LINK_ADDR0);
  
  //寄存器0x02,写0x00000001
  I2C_DMA_WriteReg(0x02, 0x00000001, &error);
  
  //读0x02寄存器
  jiCunQi_data = I2C_DMA_ReadReg(0x02, &error);
  while(1);
}




 

  • 27
    点赞
  • 149
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
STM32F103是意法半导体推出的一款高性能Cortex-M3内核的32位微控制器,具有丰富的外设资源,包括IIC接口和DMA功能。下面将简要介绍STM32F103中IICDMA的发送和接收操作。 首先,IIC接口是一种具有高速度和广泛应用的串行通信接口,适用于微控制器与外设之间的数据传输。STM32F103的IIC接口支持主机和从机模式,并能够通过硬件I2C控制器配置和驱动IIC外设。 在STM32F103中,使用DMA(Direct Memory Access)可以在不占用CPU资源的情况下实现数据的高速传输。DMA控制器是一种特殊的硬件设备,可以在外设和存储器之间直接传输数据,提高数据传输效率。 具体实现IICDMA的发送和接收操作的步骤如下: 发送操作: 1. 配置IIC的发送模式和相关参数,包括传输速率、地址等。 2. 配置DMA控制器,指定源数据地址和目标寄存器地址,并设置传输长度和传输方向。 3. 启动DMA传输并等待传输完成。 接收操作: 1. 配置IIC的接收模式和相关参数,包括传输速率、地址等。 2. 配置DMA控制器,指定源寄存器地址和目标数据地址,并设置传输长度和传输方向。 3. 启动DMA传输并等待传输完成。 4. 读取目标数据地址中的接收数据。 需要注意的是,使用DMA进行数据传输需要合理配置DMA通道和中断,可以通过DMA中断来判断传输是否完成,并及时处理传输结果。 综上所述,通过配置IIC接口和DMA控制器,可以实现在STM32F103上进行IIC数据的高速发送和接收操作,提高数据传输效率和系统性能。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值