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各种寄存器,再写写入和读出函数,然后直接把我们定义的结构体传给读或写的函数,最后在主程序调用就可以了。