STM32F4硬件IIC+DMA使用

2020-07-03来源: eefocus关键字: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));

I2

[1] [2] [3] [4]
关键字:STM32F4  硬件IIC  DMA使用 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic502062.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:stm32——串口配置一般步骤
下一篇:stm32F4之使用I2C读写24C02

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm32F4之使用I2C读写24C02
一.24C02简单介绍1.串行E2PROM是基于I2C-BUS 的存储器件,2.可以支持100万次擦除,数据可以保存100年,3.支持每次读写1字节4.写周期最大5ms(即最好保证在5ms后进行读写,否则可以数据将会读取错误)二.24C02的读写时序图从手册中可以找到以下两个读写图,我也将以以下两个图为例进行函数编写,其他读写图请查手册 三.用模拟的I2C协议封装24C02的读与写该设备为IIC设备,因此我们要先确定其设备地址,STM32F4探索者的开发板上为2K的E2PROM,A2=A1=A0  因此设备地址为(0XA0/0xA1)根据下图进行编程:字节写:使用封装好的I2C函数,进行函数24C02的写函数
发表于 2020-07-03
<font color='red'>stm32F4</font>之使用I2C读写24C02
STM32F4学习笔记之GPIO(使用固件库)
1.使能GPIO的AHB时钟,使用函数:    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE);2.配置GPIO工作模式用GPIO_Init()函数数据类型说明typedef struct{  uint32_t GPIO_Pin;              //引脚配置GPIOMode_TypeDef GPIO_Mode;  //GPIO_Mode_IN(输入),GPIO_Mode_OUT(输出),GPIO_Mode_AF(备用),GPIO_Mode_AN(模拟
发表于 2020-06-14
调用STM32F4 库函数FLASH_ProgramWord() 出错问题
最近操作STM32F4的内部flash,吓了一跳。以前的STM32F107的时候还是4k一页,现在只分了12个Sector,后面几个128K这么大。从官网下了Flash programming manual,擦除之前得清除flash flag/* Clear All pending flags */FLASH_ClearFlag( FLASH_FLAG_EOP |  FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);同时查看擦除函数,看着函数说明,正确的传参数就OK了/**  * @brief 
发表于 2020-06-09
stm32f4启动代码分析(一)
因为使用的开发板是stm32f407discovery,所以启动代码为st公司的官方库文件里的startup_stm32f40_41xxx.s,至于如何去找官方库文件,不在本节讨论的范围内,本节只是初步的分析startup_stm32f40_41xxx.s,其中更深入的东西需要在以后的章节中分析。在startup_stm32f40_41xxx.s中,有一段注释:;* File Name : startup_stm32f40_41xxx.s;* Author : MCD Application Team;* @version : V1.7.0;* @date : 22-April-2016;* Description
发表于 2020-05-08
Keil环境下STM32F4工程创建步骤
Keil环境下STM32F4工程创建步骤自己也是刚刚开始接触STM32,在开发环境配置和工程创建过程就花费了多半天的时间,写下此文以纪念自己入坑,也希望能帮助其他想要入坑的小伙伴儿顺利入坑,好了话不多说,下面请允许我开始我的表演:首先咱们需要安装MDK5和STM32F4库安装包,以及固件库压缩包,打开作者百度网盘链接:https://pan.baidu.com/s/1y4IJX6uMieAMyUXNJt0yLg提取码:nmxi下载完成后双击图标点击Next点击Next点击Next填写信息,完成后点击Nex等待安装完成。安装STM32F4库包双击图标路径会自动添加无需手动,点击Next等待安装完成至此我们的软件安装工作就算完成
发表于 2020-04-22
Keil环境下<font color='red'>STM32F4</font>工程创建步骤
MSP430F5529硬件IIC驱动IIC接口的OLED
Address is 048h    UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation    UCB0IE |= UCNACKIE;                       //使能中断}void OLED_WrCmd(unsigned char IIC
发表于 2020-07-21
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved