DSP配置I2C通讯(非IO口软件模拟时序)

1 篇文章 0 订阅
1 篇文章 0 订阅

dsp即数字信号处理器,是一种广泛应用的嵌入式处理器,主要应用是实时快速地实现各种数字信号处理算法,目前,国际主要的dsp供应商是ti公司,其tms32系列产品占据了dsp市场近一半的份额,本文以TMS320F28377D为例,使用ti公司dsp开发工具ccs10.1配置i2c模块。
写这篇文章的缘由,因为市面上很多DSP其实内部是具有硬件I2C接口的,但由于网络上大部分资料和例程都是利用IO口模拟I2C时序进而实现I2C通讯的。给很多想学习硬件I2C通讯的小伙伴带来了困难。

下面先介绍一下配置步骤
1.Enable I2C clock使能时钟
configure the PSC register(if it is driven by PSC)PSC相关说明可以查看手册
2. Configure the PinMultiplexing registers配置管脚
3. Place I2C in reset先复位I2C
set IRS =0 in ICMDR register
4.Configure the peripheral clock operation frequency(ICPSC)配置外设时钟运行频率
NOTE:the frequency should be between 6.7 and 13.3MHz(常配置为10MHZ
5.Configure i2c master clock frequency:配置I2C主时钟频率
configure ICCLKL , ICCLKH
6.Make sure the interrupt status register(ICSTR) is cleared:(配置中断
Read ICSTR and write it back (write 1 to clear) ICSTR = ICSTR
Read ICIVR until it is 0.
7.Take i2c controller out of reset 把复位关掉,即开启I2C
set IRS=1 in ICMDR

下面直接上程序进行讲解

//I2C访问EEPROM
//时间:2020.12.31
#include "F28x_Project.h"	//官方头文件
#include "SciStdio.h"			//串口头文件

// 宏定义
#define I2C_SLAVE_ADDR        0x50	
#define I2C_NUMBYTES          1
#define I2C_EEPROM_REG00        0x01
#define I2C_EEPROM_REG01        0x02

// 全局变量
struct I2CMSG I2cMsgOut1 =
{
    I2C_MSGSTAT_SEND_WITHSTOP,
    I2C_SLAVE_ADDR,
    I2C_NUMBYTES,
    0x00,                   // N/A
    I2C_EEPROM_REG00,         // 地址低位
                             //Uint16 MsgBuffer[I2C_MAX_BUFFER_SIZE];
};

struct I2CMSG I2cMsgIn1 =
{
    I2C_MSGSTAT_SEND_NOSTOP,
    I2C_SLAVE_ADDR,
    I2C_NUMBYTES,
    0x00,                   // N/A
    I2C_EEPROM_REG00,         // 地址低位
};

// I2C 初始化
void I2CA_Init(void)
{
   I2caRegs.I2CSAR.all = I2C_SLAVE_ADDR;     // 从设备地址

   I2caRegs.I2CPSC.all = 6;                  // 分频 需要 7-12 Mhz 模块时钟
   I2caRegs.I2CCLKL = 10;                    // 非零值
   I2caRegs.I2CCLKH = 5;                     // 非零值
   I2caRegs.I2CMDR.all = 0x0020;             // 解除复位 挂起时停止 I2C

   return;
}


Uint16 I2CA_WriteData(struct I2CMSG *msg)       // I2C 写数据
{
    I2caRegs.I2CSAR.all = msg->SlaveAddress;     // 设置从设备地址
    I2caRegs.I2CCNT = msg->NumOfBytes + 1;       // 设置要发送的字节数目
    I2caRegs.I2CDXR.all = msg->MemoryLowAddr;    // 设置寄存器地址
    I2caRegs.I2CMDR.all = 0x6E20;                // 配置 I2C 发送模式——FREE、STT、STP、MST、TRX、IRS

    int i;    // 开始发送数据
    for( i= 0; i < msg->NumOfBytes; i++)
    {
        while(!I2caRegs.I2CSTR.bit.XRDY);       //Transmit-data-ready interrupt flag bit.发送数据就绪中断标志位。(I2CDXR)准备好接受新数据
        I2caRegs.I2CDXR.all = *(msg->MsgBuffer + i);
    }
    while(I2caRegs.I2CSTR.bit.BB);    // 忙检测

    return I2C_SUCCESS;
}


Uint16 I2CA_ReadData(struct I2CMSG *msg)        // I2C 读数据
{
    I2caRegs.I2CSAR.all = msg->SlaveAddress;    // 设置从设备地址
    I2caRegs.I2CCNT = 1;                        // 设备地址长度
    I2caRegs.I2CDXR.all = msg->MemoryLowAddr;   // 寄存器地址
    I2caRegs.I2CMDR.all = 0x2620;               // 配置 I2C 发送    STT、MST、TRX、IRS
    DELAY_US(500);
    I2caRegs.I2CCNT = msg->NumOfBytes;          // 接收数据大小
    I2caRegs.I2CMDR.all = 0x2C20;                // 配置 I2C 接收  STT、STP、MST、Receiver mode、IRS

    int i;    //开始接收数据
    for(i = 0; i < msg->NumOfBytes; i++)
    {
        while(!I2caRegs.I2CSTR.bit.RRDY);
        *(msg->MsgBuffer + i) = I2caRegs.I2CDRR.all;
    }

   return I2C_SUCCESS;
}

void main(void)
{
    // 初始化系统控制 锁相环 看门狗 外设
    InitSysCtrl();

    // 初始化 GPIO
    InitGpio();

    GPIO_SetupPinMux(32, GPIO_MUX_CPU1, 1);
    GPIO_SetupPinMux(33, GPIO_MUX_CPU1, 1);
    EALLOW;
    GpioCtrlRegs.GPDMUX2.bit.GPIO115 = 0;   // led1
    GpioCtrlRegs.GPDDIR.bit.GPIO115 = 1;
    GpioCtrlRegs.GPDMUX2.bit.GPIO116 = 0;   // led2
    GpioCtrlRegs.GPDDIR.bit.GPIO116 = 1;
    GpioCtrlRegs.GPDMUX1.bit.GPIO111 = 0;   // led1
    GpioCtrlRegs.GPDDIR.bit.GPIO111 = 1;
    GpioCtrlRegs.GPDMUX2.bit.GPIO112 = 0;   // led2
    GpioCtrlRegs.GPDDIR.bit.GPIO112 = 1;
    GpioCtrlRegs.GPDMUX2.bit.GPIO113 = 0;   // led3
    GpioCtrlRegs.GPDDIR.bit.GPIO113 = 1;
    GpioCtrlRegs.GPDMUX2.bit.GPIO114 = 0;   // led4
    GpioCtrlRegs.GPDDIR.bit.GPIO114 = 1;
    EDIS;
    // 初始化串口
    SCIStdioInit();
    SCIPuts("\r\n ============Test Start===========.\r\n", -1);
    SCIPuts("Welcome to TL28377 I2C  Demo application.\r\n\r\n", -1);

    // 初始化外设
    I2CA_Init();

    // 清除接收缓冲区
    Uint16 i;
    for (i = 0; i < I2C_MAX_BUFFER_SIZE; i++)
    {
       I2cMsgIn1.MsgBuffer[i] = 0x0000;
    }

    for(;;)
    {
        if( I2CA_WriteData(&I2cMsgOut1) ==  I2C_SUCCESS )        // 写数据成功
        {
            SCIprintf("wwrite to EEPROM numbers:%x\n\r\n", *I2cMsgOut1.MsgBuffer);
            I2cMsgOut1.MsgBuffer[0] += 1 ;
        }
        DELAY_US(5000000);
        if( I2CA_ReadData(&I2cMsgIn1) ==  I2C_SUCCESS )        // 读数据成功
        {
            GpioDataRegs.GPDTOGGLE.bit.GPIO116 = 1;
            SCIprintf("read from EEPROM numbers:%x\n\r\n", *I2cMsgIn1.MsgBuffer);
        }

    }
}

程序上注释都很清晰,下面我总结一下程序
其实就是通过定义两个结构体(一个用于输入一个用于输出,注意:I2CMSG这个结构体在官方的I2C头文件中已经构造),然后配置I2C各种寄存器,再写写入和读出函数,然后直接把我们定义的结构体传给读或写的函数,最后在主程序调用就可以了。

以下是DSP28335通过I2C外扩M24M02存储大量数据的代码,包括初始化、写入和读取操作。 初始化: ```c #include "DSP2833x_Device.h" #include "DSP2833x_Examples.h" #include "DSP2833x_I2C.h" #define M24M02_I2C_ADDR 0x50 // M24M02 I2C地址 void InitI2C(void) { // 初始化I2C总线 I2caRegs.I2CSAR = M24M02_I2C_ADDR; // 设置I2C从设备地址 I2caRegs.I2CPSC.all = 6; // 设置I2C时钟分频,SYSCLKOUT/(I2CPSC+1) = 150MHz/(6+1) = 21.43MHz I2caRegs.I2CCLKL = 10; // 设置I2C时钟低电平时间,21.43MHz/(10+1) = 1.87MHz I2caRegs.I2CCLKH = 5; // 设置I2C时钟高电平时间,21.43MHz/(5+1) = 3.57MHz I2caRegs.I2CIER.all = 0x24; // 使能I2C中断,接收数据中断和总线错误中断 I2caRegs.I2CMDR.all = 0x0020; // 使能I2C模块,无主模式 } ``` 写入数据: ```c void WriteToM24M02(unsigned int address, unsigned char *data, unsigned int length) { unsigned int i; I2caRegs.I2CCNT = length; // 设置数据长度 I2caRegs.I2CDXR = address >> 8; // 发送数据地址高字节 I2caRegs.I2CDXR = address & 0xFF; // 发送数据地址低字节 for (i = 0; i < length; i++) { I2caRegs.I2CDXR = data[i]; // 发送数据 while (I2caRegs.I2CSTR.bit.ARDY == 0); // 等待发送完成 } } ``` 读取数据: ```c void ReadFromM24M02(unsigned int address, unsigned char *data, unsigned int length) { unsigned int i; I2caRegs.I2CCNT = 2; // 先发送数据地址 I2caRegs.I2CDXR = address >> 8; // 发送数据地址高字节 I2caRegs.I2CDXR = address & 0xFF; // 发送数据地址低字节 I2caRegs.I2CCNT = length; // 再接收数据 I2caRegs.I2CDXR = (M24M02_I2C_ADDR << 1) | 1; // 发送读命令 for (i = 0; i < length; i++) { while (I2caRegs.I2CSTR.bit.RRDY == 0); // 等待接收完成 data[i] = I2caRegs.I2CDRR; // 读取数据 } } ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值