打印
[KungFu32位 MCU]

KF32F350_demo-I2C通过DMA读写外部eeprom

[复制链接]
2804|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
静听风易|  楼主 | 2020-10-25 21:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
main.c
/****************************************************************************************
*
* 文件名: main.c
* 项目名: EEPROM_DMA
* 版 本:  V2.1
* 日 期:  2019年11月16日
* 作 者:  ChipON_AE/FAE_Group
*
****************************************************************************************/
#include "system_init.h"
#include "EEPROM_24LC256.h"
#include "Usart.h"




/**
  * 描述  GPIOx 输出初始化配置。
  * 输入 : GPIOx: 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。
  *       GpioPin: 端口引脚掩码,取值为GPIO_PIN_MASK_0~GPIO_PIN_MASK_15中的一个或多个组合。
  * 返回  无。
  */
void GPIOInit_Output_Config(GPIO_SFRmap* GPIOx,uint16_t GpioPin)
{
        /*初始化复位GPIOx外设,使能GPIOx外设时钟*/
                GPIO_Reset(GPIOx);

        /* 配置 Pxy作为输出模式参数 */
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_Struct_Init(&GPIO_InitStructure);
        GPIO_InitStructure.m_Pin = GpioPin;
        GPIO_InitStructure.m_Speed = GPIO_LOW_SPEED;          //初始化 GPIO输出速度
        GPIO_InitStructure.m_Mode = GPIO_MODE_OUT;            //初始化 GPIO方向为输出
        GPIO_InitStructure.m_PullUp = GPIO_NOPULL;            //初始化 GPIO是否上拉
        GPIO_InitStructure.m_PullDown = GPIO_NOPULL;          //初始化 GPIO是否下拉
        GPIO_Configuration(GPIOx,&GPIO_InitStructure);

        GPIO_Set_Output_Data_Bits(GPIOx,GpioPin,Bit_SET);          //先设置为高电平

}

/**
  * 描述  I2Cx引脚上拉初始化及重映射配置。
  * 输入  无
  *
  * 返回  无。
  */
void I2C_GPIO_init(void)
{
        /*I2Cx引脚上拉初始化及重映射配置*/
        GPIO_InitTypeDef I2C_GPIO_Init;

        I2C_GPIO_Init.m_Mode = GPIO_MODE_RMP;                   //GPIO设为重映射
        I2C_GPIO_Init.m_OpenDrain = GPIO_POD_OD;                //GPIO设为开漏输出
        I2C_GPIO_Init.m_Pin = GPIO_PIN_MASK_0|GPIO_PIN_MASK_1;  //选用的GPIO端口
        I2C_GPIO_Init.m_PullUp = GPIO_PULLUP;                   //GPIO设为上拉
        I2C_GPIO_Init.m_PullDown = GPIO_NOPULL;                 //GPIO不下拉
        I2C_GPIO_Init.m_Speed = GPIO_HIGH_SPEED;                //GPIO速度设为高速
        GPIO_Pin_RMP_Config(GPIOA_SFR,GPIO_Pin_Num_0,GPIO_RMP_AF8_I2C0);  //设PA0为I2C0的SDA
        GPIO_Pin_RMP_Config(GPIOA_SFR,GPIO_Pin_Num_1,GPIO_RMP_AF8_I2C0);  //设PA1为I2C0的SCK

        GPIO_Configuration(GPIOA_SFR,&I2C_GPIO_Init);

}

/**
  * 描述  初始化I2Cx参数配置波特率设置。
  * 输入  I2Cx:指向I2C内存结构的指针,取值为I2C0_SFR~I2C3_SFR。
  *
  * 返回  无。
  */
void I2C_init(I2C_SFRmap* I2Cx)
{
        /*I2Cx*/
        I2C_Reset(I2Cx);
        I2C_InitTypeDef newStruct_I2C;
        newStruct_I2C.m_Mode = I2C_MODE_I2C;              //I2C模式
        newStruct_I2C.m_ClockSource = I2C_CLK_SCLK;      //采用主频120M,一个时钟周期为0.00833us
        newStruct_I2C.m_BADR10 = I2C_BUFRADDRESS_7BIT;    //7位的地址模式
        newStruct_I2C.m_MasterSlave = I2C_MODE_SMBUSHOST; //SMBus类型选择:HOST
        newStruct_I2C.m_BaudRateL = 150;                   //波特率低电平时间:150X0.00833us=1.25us
        newStruct_I2C.m_BaudRateH = 150;                   //波特率高电平时间:150X0.00833us=1.25us 得到400KHZ
        newStruct_I2C.m_AckEn = TRUE;                     //ACK应答使能
        newStruct_I2C.m_AckData = I2C_ACKDATA_ACK;        //应答ACK
        I2C_Configuration(I2Cx, &newStruct_I2C);

        /*使能I2C模块*/
        I2C_Cmd(I2Cx,TRUE);
        I2C_Clear_INTERRUPT_Flag(I2Cx);  //清I2C中断标志位

}



//主函数
void main()
{
        /*用户可参考该例程在KF32F350_demo板上实现I2C主模式的DMA写外部的EERPOM功能,并读出写入的数据与写入数据作对比。
        * 例程中使用I2C0 PA0 PA1用于主机I2C通信,DMA请求由I2C0触发。EEPROM 24LC256最高支持400KHZ。
        * 功能简述:        KF32F350通过I2C总线DMA传输的方式在EERPOM的0x0000地址写入64个字节数据,然后用CPU读形式从0x0000地址再读出64个字节数据进行对比,
        *           数据匹配后PB8翻转LED0闪烁,否则PB9翻转LED1闪烁
        * 硬件说明:    设PA0为I2C0的SDA  设PA1为I2C0的SCK
        *            PB8对应控制LED0灯\PB9对应控制LED1灯\PB10对应控制LED2灯
        *           如果需要用串口接USART0_RX PB6         USART0_TX0        PB7  并在Usart.h打开 串口宏定义Usart_Print  1
        *EERPOM:型号为24LC256
        *注:DMA传输完成标志置位是在传输完倒数第一个之前就会发生,
    */

        //系统时钟96M,外设高频时钟16M
        SystemInit();//系统时钟初始化
        /*PB8 PB9 初始化设为输出高电平*/
        GPIOInit_Output_Config(GPIOB_SFR,GPIO_PIN_MASK_8|GPIO_PIN_MASK_9);

        //I2C GPIO选用及功能重映射
        I2C_GPIO_init();      //设PA0为I2C0的SDA  设PA1为I2C0的SCK
        //初始化I2C0模块参数
        I2C_init(I2C0_SFR);   //波特率设为400KHZ

#if Usart_Print
        GPIO_USART();//配置USART0引脚重映射,        //USART2_RX                PB15         USART2_TX0        PB14
        USART_Async_config(USART2_SFR);//全双工异步8bit 9600波特率
#endif
        while(1)
    {
                if(I2C_OK == AT24LC256_TEST_DMA())//判断DMA写的数据与读出的数据是否匹配
                {
                        GPIO_Toggle_Output_Data_Config(GPIOB_SFR,GPIO_PIN_MASK_8);//数据匹配后,PB8翻转,LED0闪烁
                        delay_ms(1000);
                }else
                {
                        GPIO_Toggle_Output_Data_Config(GPIOB_SFR,GPIO_PIN_MASK_9);//PB9翻转
                        delay_ms(1000);
                }
#if Usart_Print
                //串口打印读到的数组数据
                USART_Send(USART2_SFR,i2c_buffer_read,sizeof(i2c_buffer_read));
                delay_ms(1000);
#endif


    }

}



/**
  * 描述   报告校验发生错误的文件和行
  * 输入   file: 指向文件名称的指针
  *      line: 校验错误的行
  * 返回  无。
  */
void check_failed(uint8_t* file, uint32_t line)
{
          /* 用户可以添加自己的代码实现报告文件名和行号,
                     例如: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

          while(1)
          {
                  ;
          }
}



使用特权

评论回复
沙发
静听风易|  楼主 | 2020-10-25 21:49 | 只看该作者
EEPROM_24LC256.c
/**
  ********************************************************************
  * 文件名  EEPROM_24LC256.c
  * 作  者   ChipON_AE/FAE_Group
  * 版  本  V2.1
  * 日  期  2019-11-16
  * 描  述  该文件提供了EERPOM读写功能函数等相关函数。
  *
  *********************************************************************
*/
#include "system_init.h"
#include "EEPROM_24LC256.h"


#define I2C_Buffer_Addr   0x40000D08   //I2C0  Buffer 地址

I2C_SFRmap* I2C_Choose;    //定义I2C变量,取值 为I2C0_SFR~I2C3_SFR



//延时函数 局部变量用volatile声明,否则可能会被优化
void Delay(volatile uint32_t cnt)
{
        while(cnt--);
}

void delay_ms(volatile uint32_t nms)
{
        volatile uint32_t i,j;
        for(i=0;i<nms;i++)
        {
                j=800;
                while(j--);
        }

}

/**
  * 描述  eeprom 写入单字节数据。
  * 输入  write_address:eeprom 16位寄存器地址
  *           p_buffer: 写入数据,取值为10位数据。
  * 返回  无。
  */
void eeprom_byte_write(uint16_t write_address,uint32_t p_buffer)
{

        I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR
        static uint8_t EEPROM_AddH=0;
        static uint8_t EEPROM_AddL=0;

        EEPROM_AddL=write_address& 0xff;                //低8位寄存器地址
        EEPROM_AddH=(write_address>>8)& 0xff;           //高8位寄存器地址

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清I2C中断标志位ISIF位
        I2C_Cmd(I2C_Choose,TRUE);                       //使能I2C模块

        /*起始位*/
        I2C_Generate_START(I2C_Choose,TRUE);            //使能起始信号
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));     //等待起始位稳定


        /*发送I2C从机地址*/
        I2C_SendData(I2C_Choose,EEPROM_I2C_ADDRESS);   //发送从机I2C地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));     //等待发送完成


        /*发送高位地址*/
        I2C_SendData(I2C_Choose,EEPROM_AddH);          //发送从机高位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);          //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));    //等待发送完成

        /*发送低位地址*/
        I2C_SendData(I2C_Choose,EEPROM_AddL);          //发送从机低位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);          //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));    //等待发送完成


        /*发送数据*/
        I2C_SendData(I2C_Choose, p_buffer);            //发送8位数据
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);          //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));    //等待发送完成


        /*停止位*/
        I2C_Generate_STOP(I2C_Choose,TRUE);         //使能停止信号

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        I2C_Clear_Stop_Flag(I2C_Choose);            //清I2C停止标志位PIF位
        I2C_Cmd(I2C_Choose,FALSE);                  //关闭I2C模块

}

/**
  * 描述  eeprom 写入多字节数据。
  * 输入  write_address:eeprom 16位寄存器地址
  *           p_buffer: 写入数据指针
  *      number_of_byte:写入数据长度
  * 返回  无。
  */
void eeprom_buffer_write(uint16_t Write_address,uint8_t *p_buffer,uint16_t number_of_byte)
{
        I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR

        static uint8_t EEPROM_AddH=0;
        static uint8_t EEPROM_AddL=0;

        EEPROM_AddL=Write_address& 0xff;                     //低8位寄存器地址
        EEPROM_AddH=(Write_address>>8)& 0xff;                //高8位寄存器地址

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                //清I2C中断标志位ISIF位
        I2C_Cmd(I2C_Choose,TRUE);                            //使能I2C模块
        /*起始位*/
        I2C_Generate_START(I2C_Choose,TRUE);                 //使能起始信号
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));



        /*发送I2C从机地址*/
        I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS);        //发送从机I2C地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                    //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));              //等待发送完成
        while(I2C_Get_Ack_Fail_Flag(I2C_Choose));    //判断是否有ACK应答,如没有则停止,如果有则继续发


        /*发送高位地址*/
        I2C_SendData8(I2C_Choose,EEPROM_AddH);            //发送从机高位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));          //等待发送完成

        /*发送低位地址*/
        I2C_SendData8(I2C_Choose,EEPROM_AddL);            //发送从机低位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));          //等待发送完成

    /* 循环写数据操作 */
    while(number_of_byte--){
            I2C_SendData8(I2C_Choose, *p_buffer);        //发送8位数据
            I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清I2C中断标志位ISIF位
        /* 指向下一个所要写的字节 */
        p_buffer++;
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));     //等待发送完成

    }

        /*停止位*/
        I2C_Generate_STOP(I2C_Choose,TRUE);         //使能停止信号

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        I2C_Clear_Stop_Flag(I2C_Choose);            //清I2C停止标志位PIF位
        I2C_Cmd(I2C_Choose,FALSE);                  //关闭I2C模组

}



/**
  * 描述  eeprom 读出单字节数据。
  * 输入  write_address:eeprom 16位寄存器地址
  *           p_buffer: 读出数据,取值为8位数据。
  * 返回  无。
  */
void eeprom_byte_read(uint16_t Write_address,uint8_t p_buffer)
{
        I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR

        static uint8_t EEPROM_AddH=0;
        static uint8_t EEPROM_AddL=0;


        EEPROM_AddL=Write_address& 0xff;//低8位寄存器地址
        EEPROM_AddH=(Write_address>>8)& 0xff;  //高8位寄存器地址

        I2C_Cmd(I2C_Choose,TRUE);

        /*起始位*/
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清I2C中断标志位ISIF位
        I2C_Generate_START(I2C_Choose,TRUE);            //使能起始信号
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));     //等待起始位稳定


        /*发送I2C从机地址*/
        I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS);        //发送从机I2C地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                    //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));              //等待发送完成
        while(I2C_Get_Ack_Fail_Flag(I2C_Choose));    //判断是否有ACK应答,如没有则停止,如果有则继续发


        /*发送要读寄存器高位地址*/
        I2C_SendData8(I2C_Choose,EEPROM_AddH);                 //发送从机高位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                     //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));                //等待发送完成


        /*发送要读寄存器低位地址*/
        I2C_SendData8(I2C_Choose,EEPROM_AddL);                 //发送从机低位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                     //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));               //等待发送完成


        I2C_Cmd(I2C_Choose,FALSE);                              //关I2C模块

        I2C_Clear_Start_Flag(I2C_Choose);                       //清I2C起始标志位SIF位
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                  //清I2C中断标志位ISIF位
        I2C_Cmd(I2C_Choose,TRUE);                               //使能I2C模块
        /*起始位*/
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                 //清I2C中断标志位ISIF
        I2C_Generate_START(I2C_Choose,TRUE);                  //使能起始信号
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));           //等待起始信号稳定


        /*发送读指令*/
        I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS|0x01);//发送从机地址及读操作
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清标志位ISIF位

        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));     //等待发送完成ISIF会置1
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //然后完成清标志位ISIF位


        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));  //等待读取Buff完成ISIF会置1
        if(I2C_Get_Receive_Buff_Flag(I2C_Choose))     //判断Buff是否为满
        {
                I2C_Ack_DATA_Config(I2C_Choose,I2C_ACKDATA_ACK);//回复ACK
                p_buffer = I2C_ReceiveData(I2C_Choose);
                 I2C_Clear_INTERRUPT_Flag(I2C_Choose);        //然后读完后清标志位ISIF位

        }


    while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));
        /*停止位*/
        I2C_Generate_STOP(I2C_Choose,TRUE);         //使能停止信号

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        I2C_Clear_Stop_Flag(I2C_Choose);            //清I2C停止标志位PIF位
        I2C_Cmd(I2C_Choose,FALSE);                  //关闭I2C模组


}






/**
  * 描述  eeprom 读出多字节数据。
  * 输入  write_address:eeprom 16位寄存器地址
  *           p_buffer: 读出数据指针
  *      number_of_byte:读出数据长度
  * 返回  无。
  */
void eeprom_buffer_read(uint16_t Write_address,uint8_t *p_buffer,uint16_t number_of_byte)
{
        I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR

        static uint8_t EEPROM_AddH=0;
        static uint8_t EEPROM_AddL=0;

        EEPROM_AddL=Write_address& 0xff;       //低8位寄存器地址
        EEPROM_AddH=(Write_address>>8)& 0xff;  //高8位寄存器地址

        I2C_Cmd(I2C_Choose,TRUE);                            //使能I2C3模块

        /*起始位*/
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                //清I2C中断标志位ISIF位
        I2C_Generate_START(I2C_Choose,TRUE);                 //使能起始信号
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));          //等待起始位稳定



        /*发送I2C从机地址*/
        I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS);     //发送从机I2C地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                 //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));           //等待发送完成
        while(I2C_Get_Ack_Fail_Flag(I2C_Choose));    //判断是否有ACK应答,如没有则停止,如果有则继续发


        /*发送要读寄存器高位地址*/
        I2C_SendData8(I2C_Choose,EEPROM_AddH);            //发送从机高位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));           //等待发送完成


        /*发送要读寄存器低位地址*/
        I2C_SendData8(I2C_Choose,EEPROM_AddL);            //发送从机低位寄存器地址
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));          //等待发送完成


        I2C_Cmd(I2C_Choose,FALSE);                       //关I2C模块

        I2C_Clear_Start_Flag(I2C_Choose);               //清I2C起始标志位SIF位
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清标志位ISIF位
        I2C_Cmd(I2C_Choose,TRUE);                       //打开I2C模块
        /*起始位*/
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清中断标志位ISIF位
        I2C_Generate_START(I2C_Choose,TRUE);             //起始信号
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));     //等待起始位稳定


        /*发送读指令*/
        I2C_SendData8(I2C_Choose,EEPROM_I2C_ADDRESS|0x01);//发送从机地址及读操作
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //清标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));     //等待发送完成ISIF会置1
        while(I2C_Get_Ack_Fail_Flag(I2C_Choose));    //判断是否有ACK应答,如没有则停止,如果有则继续发
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);           //然后完成清标志位ISIF位


        while(number_of_byte)
        {
                while(!I2C_Get_INTERRUPT_Flag(I2C_Choose));  //等待读取Buff完成ISIF会置1
                if(I2C_Get_Receive_Buff_Flag(I2C_Choose))     //判断Buff是否为满
                {
                        *p_buffer = I2C_ReceiveData(I2C_Choose);
                         I2C_Ack_DATA_Config(I2C_Choose,I2C_ACKDATA_ACK);//回复ACK
                         I2C_Clear_INTERRUPT_Flag(I2C_Choose);        //然后读完后清标志位ISIF位
                         p_buffer++;      /* 指向下一个被读取的字节将被保存的位置 */

                  /* 递减读取字节计数*/
                   number_of_byte--;

                }

//                if(number_of_byte==1)
//                {
//                  I2C_Generate_STOP(I2C_Choose,TRUE);         //使能停止信号
//                 I2C_Clear_INTERRUPT_Flag(I2C_Choose);        //然后读完后清标志位ISIF位
//                }

        }


        /*停止位*/
        I2C_Generate_STOP(I2C_Choose,TRUE);         //使能停止信号

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        I2C_Clear_Stop_Flag(I2C_Choose);            //清I2C停止标志位PIF位
        I2C_Cmd(I2C_Choose,FALSE);                  //关闭I2C模组


}





/**
  * 描述  I2C_DMA 初始化。
  * 输入  无
  *
  * 返回  无。
  */
void I2C_DMA_Init(void)
{

        uint32_t *I2C_write_ADDR=&i2c_buffer_write[0];
        DMA_InitTypeDef I2C_DMAStruct;
        //注意:DMA传感完成标志产生是在传输完成倒数第一个时就会置位
        I2C_DMAStruct.m_Number = WRITE_BUFFER_SIZE+1;/* 配置 传输数据个数: WRITE_BUFFER_SIZE+1 */

        I2C_DMAStruct.m_Direction = DMA_MEMORY_TO_PERIPHERAL;/* 配置 DMA传输方向: 内存到外设*/
        I2C_DMAStruct.m_Priority = DMA_CHANNEL_LOWER;/* 配置 DMA通道优先级:低优先级 */
        I2C_DMAStruct.m_PeripheralDataSize = DMA_DATA_WIDTH_8_BITS;/* 配置 外设数据位宽:8位宽 */
        I2C_DMAStruct.m_MemoryDataSize = DMA_DATA_WIDTH_8_BITS;/* 配置 存储器数据位宽:8位宽 */
        I2C_DMAStruct.m_PeripheralInc = FALSE;/* 配置 外设地址增量模式使能: 不使能 */
        I2C_DMAStruct.m_MemoryInc = TRUE;/* 配置 存储器地址增量模式使能: 使能 */
        I2C_DMAStruct.m_Channel = DMA_CHANNEL_4;/* 配置 DMA通道选择:通道4 */
        I2C_DMAStruct.m_BlockMode = DMA_TRANSFER_BYTE; /* 配置 数据块传输模式: */
        I2C_DMAStruct.m_LoopMode = TRUE;/* 配置 循环模式使能: 禁止 */
        I2C_DMAStruct.m_PeriphAddr = I2C_Buffer_Addr;/* 配置 外设起始地址:等待发送的数据的起始地址 */
        I2C_DMAStruct.m_MemoryAddr = I2C_write_ADDR;/* 配置 内存起始地址:接收数据的内存空间的起始地址 */
        DMA_Reset(DMA0_SFR);
        DMA_Configuration(DMA0_SFR, &I2C_DMAStruct);

}

void DMA_I2C_Enable(FunctionalState NewState)
{
        I2C_Choose=I2C0_SFR;//选择I2C0_SFR I2C1_SFR I2C2_SFR I2C3_SFR

        I2C_Transmit_DMA_INT_Enable(I2C_Choose,NewState);    //使能 I2C0发送DMA中断
        DMA_Channel_Enable(DMA0_SFR,DMA_CHANNEL_4,NewState); //配置使能DMA0 通道4
        /*发送*/
        I2C_Cmd(I2C_Choose,TRUE);                            //使能I2C模块
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);                 //清中断标志ISIF
        I2C_Generate_START(I2C_Choose,TRUE);                  //开起始信号


        while(!DMA_Get_Finish_Transfer_INT_Flag(DMA0_SFR,DMA_CHANNEL_4));  //等待DMA传输完成
        if(!I2C_Get_Transmit_Buff_Flag(I2C_Choose))    //读取Buff状态,为空则释放总线
        {
                /*停止位*/
                I2C_Generate_STOP(I2C_Choose,TRUE);         //使能停止信号
                I2C_Clear_INTERRUPT_Flag(I2C_Choose);       ////清中断标志ISIF
        }

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        while(!I2C_Get_INTERRUPT_Flag(I2C_Choose)); //等待停止完成

        I2C_Clear_INTERRUPT_Flag(I2C_Choose);       //清I2C中断标志位ISIF位
        I2C_Clear_Stop_Flag(I2C_Choose);            //清I2C停止标志位PIF位
        I2C_Cmd(I2C_Choose,FALSE);                            //使能I2C模块


}


/**
  * 描述  先写64个字节数据并读出64个字节数据进行比较。
  * 输入  无
  * 返回 1 :数据对比匹配。
  *     0 :数据对比不匹配。
  */
uint8_t AT24LC256_TEST_DMA(void)
{
        volatile   uint16_t i;
        i2c_buffer_write[0]=EEPROM_I2C_ADDRESS; // EEPROM I2C 地址定义
        i2c_buffer_write[1]=EEPROM_ADDH;        // EEPROM I2C 高8位寄存器地址定义
        i2c_buffer_write[2]=EEPROM_ADDL;        // EEPROM I2C 低8位寄存器地址定义

        /* 初始化i2c写缓冲区 */
    for(i = 3;i < WRITE_BUFFER_SIZE;i++)
    {
        i2c_buffer_write[i]=i-3;   //0~0X3F
    }
    Delay(0XFFFF);
    Delay(0XFFFF);
    /* 使用DMA 写EERPOM 数据*/
    I2C_DMA_Init();   //初始化I2C DMA
        DMA_I2C_Enable(TRUE);   //使能DMA 通道及I2C触发DMA
    Delay(0XFFFF);
    Delay(0XFFFF);
    Delay(0XFFFF);
        I2C_Transmit_DMA_INT_Enable(I2C0_SFR,FALSE);      //关 I2C0发送DMA中断
        DMA_Channel_Enable(DMA0_SFR,DMA_CHANNEL_4,FALSE); //关DMA0 通道4
    Delay(0XFFFF);
    Delay(0XFFFF);
    Delay(0XFFFF);
    Delay(0XFFFF);
    Delay(0XFFFF);
    /* 读取EEPROM 数据 */
    eeprom_buffer_read(EEP_FIRST_PAGE,i2c_buffer_read,sizeof(i2c_buffer_read));
    Delay(0XFFFF);
    Delay(0XFFFF);
    Delay(0XFFFF);
    Delay(0XFFFF);
    Delay(0XFFFF);
    ///写入的EEPROM数据和读出的EERPOM数据对比
    for(i = 0;i < READ_BUFFER_SIZE;i++)
    {
        if(i2c_buffer_read[i] != i2c_buffer_write[i+3])
        {
           return I2C_FAIL;
        }
    }
    return I2C_OK;
}








使用特权

评论回复
板凳
静听风易|  楼主 | 2020-10-25 21:49 | 只看该作者
system_init.c
/**
  ******************************************************************************
  * 文件名  system_init.c
  * 作  者  ChipON_AE/FAE_Group
  * 版  本  V2.1
  * 日  期  2019-11-16
  * 描  述  该文件提供了外设时钟与系统时钟初始化
  *
  ******************************************************************************
  */
#include "system_init.h"
/**
  * 描述  时钟默认配置。
  * 输入  无。
  * 返回  无。
*/
static void SetSysClock(void)
{
        /* 使能内部高频时钟*/
        OSC_INTHF_Software_Enable(TRUE);
        while(OSC_Get_INTHF_INT_Flag() != SET);
        /* PLL时钟源选择 */
#ifdef SYSCLK_FREQ_HSI
        OSC_PLL_Input_Source_Config(PLL_INPUT_INTHF);
#else
        OSC_PLL_Input_Source_Config(PLL_INPUT_EXTHF);
#endif
        /* PLL倍频时钟选择 */
#ifdef SYSCLK_FREQ_48MHz
        OSC_PLL_Multiple_Value_Select(48,2,8);
#elif defined SYSCLK_FREQ_72MHz
        OSC_PLL_Multiple_Value_Select(36,2,4);
#elif defined SYSCLK_FREQ_96MHz
        OSC_PLL_Multiple_Value_Select(12,1,2);
#elif defined SYSCLK_FREQ_120MHz
        OSC_PLL_Multiple_Value_Select(30,2,2);
#endif
        OSC_PLL_Start_Delay_Config(PLL_START_DELAY_1024);
        OSC_PLL_Software_Enable(TRUE);
        OSC_PLL_RST();
        while(OSC_Get_PLL_INT_Flag() != SET);
        /* 主时钟配置 */
        OSC_SCK_Division_Config(SCLK_DIVISION_1);
        OSC_SCK_Source_Config(SCLK_SOURCE_PLL);
        /* 外设高速时钟 */
        OSC_HFCK_Division_Config(HFCK_DIVISION_1);
        OSC_HFCK_Source_Config(HFCK_SOURCE_INTHF);
        OSC_HFCK_Enable(TRUE);

        OSC_LFCK_Division_Config(LFCK_DIVISION_1);                //低频工作分频选择
        OSC_LFCK_Source_Config (LFCK_INPUT_INTLF);                //选择INTLF作为LFCLK时钟
        OSC_LFCK_Enable (TRUE);                                                        //LFCLK时钟信号允许
        OSC_INTLF_Software_Enable(TRUE);
        OSC_INTHF_Software_Enable(TRUE);                                //内部高频振荡器软件使能
}

/**
  * 描述  系统初始化。
  * 输入  无。
  * 返回  无。
*/
void SystemInit(void)
{
        /* 时钟配置 */
        SetSysClock();
}

使用特权

评论回复
地板
静听风易|  楼主 | 2020-10-25 21:50 | 只看该作者
Usart.c
/**
  ********************************************************************
  * 文件名  Usart.c
  * 作  者   ChipON_AE/FAE_Group
  * 版  本  V2.1
  * 日  期  2019-11-16
  * 描  述  该文件提供了Usart GPIO初始化、Usart配置参数、Usart发送函数等相关函数。
  *
  *********************************************************************
*/
#include "system_init.h"




/**
  * 描述   串口GPIO重映射
  * 输入   无
  * 返回   无
  */
void GPIO_USART(void)
{
         /* 端口重映射AF5 */
        //USART2_RX                PB15
        //USART2_TX0        PB14
        GPIO_Write_Mode_Bits(GPIOB_SFR ,GPIO_PIN_MASK_14, GPIO_MODE_RMP);           //重映射IO口功能模式
        GPIO_Write_Mode_Bits(GPIOB_SFR ,GPIO_PIN_MASK_15, GPIO_MODE_RMP);           //重映射IO口功能模式
        GPIO_Pin_RMP_Config (GPIOB_SFR, GPIO_Pin_Num_14, GPIO_RMP_AF5_USART2);           //重映射为USART2
        GPIO_Pin_RMP_Config (GPIOB_SFR,GPIO_Pin_Num_15, GPIO_RMP_AF5_USART2);       //重映射为USART2
        GPIO_Pin_Lock_Config (GPIOB_SFR ,GPIO_PIN_MASK_14, TRUE);                   //配置锁存
        GPIO_Pin_Lock_Config (GPIOB_SFR ,GPIO_PIN_MASK_15, TRUE);                   //配置锁存

}

/**
  * 描述   串口发送
  * 输入   USARTx:   指向USART内存结构的指针,取值为USART0_SFR~USART8_SFR
  *      Databuf:   指向发送数据的指针
  *      length:      发送的长度
  * 返回   无
  */
void USART_Send(USART_SFRmap* USARTx, uint8_t* Databuf, uint32_t length)
{
        uint32_t i;
        for(i=0;i<length;i++)
        {
                //串口发送
                USART_SendData(USARTx,Databuf[i]);
                //发送完成标志
                while(!USART_Get_Transmitter_Empty_Flag(USARTx));
        }
}


/**
  * 描述  串口异步全双工配置(默认8bit收发使能  全双工 9600)
  * 输入   指向USART内存结构的指针,取值为USART0_SFR~USART8_SFR
  * 返回   无
  */
void USART_Async_config(USART_SFRmap *USARTx)
{
        USART_InitTypeDef USART_InitStructure;

        USART_Struct_Init(&USART_InitStructure);
    USART_InitStructure.m_Mode=USART_MODE_FULLDUPLEXASY;                        //全双工
    USART_InitStructure.m_TransferDir=USART_DIRECTION_FULL_DUPLEX;              //传输方向
    USART_InitStructure.m_WordLength=USART_WORDLENGTH_8B;                       //8位数据
    USART_InitStructure.m_StopBits=USART_STOPBITS_1;                            //1位停止位
    USART_InitStructure.m_BaudRateBRCKS=USART_CLK_HFCLK;                        //内部高频时钟作为 USART波特率发生器时钟

    /* 波特率 =Fck/(16*z(1+x/y)) 外设时钟内部高频16M*/
    //4800    z:208    x:0    y:0
    //9600    z:104    x:0    y:0
    //19200   z:52     x:0    y:0
    //115200  z:8      x:1    y:13
    //波特率9600
    USART_InitStructure.m_BaudRateInteger=104;         //USART波特率整数部分z,取值为0~65535
    USART_InitStructure.m_BaudRateNumerator=0;         //USART波特率小数分子部分x,取值为0~0xF
    USART_InitStructure.m_BaudRateDenominator=0;       //USART波特率小数分母部分y,取值为0~0xF

        USART_Reset(USARTx);                                       //USARTx复位
        USART_Configuration(USARTx,&USART_InitStructure);          //USARTx配置
        USART_Clear_Transmit_BUFR_INT_Flag(USARTx);                //USARTx发送BUF清零
        USART_RESHD_Enable (USARTx, TRUE);                                                   //使能RESHD位
        USART_Cmd(USARTx,TRUE);                                    //USARTx使能
}

使用特权

评论回复
5
别看我照片| | 2020-10-29 09:23 | 只看该作者
想问一下,是否可以使用外部EEPROM进行程序升级。或者将BOOT烧录到EEPROM里面?

使用特权

评论回复
6
自己的灌饼| | 2020-10-29 09:31 | 只看该作者
有没有DMA+串口的代码,是不是直接可以实现透传的方式?

使用特权

评论回复
7
答案很长吧| | 2020-10-29 09:40 | 只看该作者
最好是分享一下工程文件,感谢楼主耐心细致的工作。

使用特权

评论回复
8
自己造声卡| | 2020-10-29 09:49 | 只看该作者
楼主,可以分享一下工程文件吗?我感觉我的工程,复制粘贴之后,运行之后,出现问题,无法仿真,好像哪里设置的有问题,可以分享一下整个工程文件吗?我比较一下。

使用特权

评论回复
9
发的非官方的| | 2020-10-31 20:37 | 只看该作者
是否可以使用外部EEPROM进行程序升级

使用特权

评论回复
10
发的非官方的| | 2020-10-31 20:38 | 只看该作者
有没有DMA+串口的代码

使用特权

评论回复
11
yinzechi| | 2024-8-2 14:05 | 只看该作者
学习了,楼主是否使用过EEPROM进行程序升级?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

231

帖子

0

粉丝