XFS5152CE芯片STM32的GPIO模拟I2C驱动播报语音

本文介绍如何使用STM32的GPIO模拟I2C接口,驱动科大讯飞的XFS5152CE TTS语音合成芯片。详细解释了硬件连接、软件驱动编写及调试过程,包括位带操作、GPIO控制宏定义、I2C通信函数等。

XFS5152CE是科大讯飞的TTS语音合成芯片,提供UART,SPI,I2C三种接口为用户实现TTS语音数据的传输播报。下面以STM32为主设备用I2C接口方式进行语音芯片的驱动,XFS5152CE作为从设备,接收主设备发过来的播报数据帧进行处理播报输出。

由官方提供的芯片用户手册,我们可以参考器电路原理进行硬件连接,参考其i2c接口提示,进行软件驱动的编写与调试。

由于说STM32的片上外设i2c存在一定缺陷,而且XFS5152CE芯片的i2c通信速率比较慢(硬件i2c通常速率较高),这里STM32F103我使用的是GPIO模拟I2C的方案,速度也比较好控制,即采用延时函数实现通信时钟SCL的控制。

user_i2c.h



#ifndef __USER_IIC_H__
#define __USER_IIC_H__


#include "stm32f10x.h"
#include "stm32f10x_i2c.h"

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

//IO方向设置
#define SDA_IN()  {GPIOD->CRH&=0X0FFFFFFF;GPIOD->CRH|=8<<28;}
#define SDA_OUT() {GPIOD->CRH&=0X0FFFFFFF;GPIOD->CRH|=3<<28;}

//IO操作函数	 
#define IIC_SCL    PDout(14) //SCL
#define IIC_SDA    PDout(15) //SDA	 
#define READ_SDA   PDin(15)  //输入SDA 

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte();//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void XFS5152CE_IIC_WriteBytes(unsigned char* buf, int len);
u8 XFS5152CE_IIC_ReadOneByte(u8 addr);
void TTStest(void);


#endif

user_i2c.c


/*
本文件为STM32正对于科大讯飞的语音合成芯片XFS5152CE进行I2C驱动实现语音的播报驱动
为保证通讯稳定性,XFS5152CE的i2c接口通信速度要求不高于15KHZ
本示例使用io模拟i2c实现对XFS5152CE的数据写读
*/

#include "user_i2c.h"
#include "user_delay.h"
#include "user_usart1.h"

#define I2C_Speed 20 //us


void IIC_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	IIC_SCL=1;
	IIC_SDA=1;
} 
 
//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	DELAY_Us(I2C_Speed);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	DELAY_Us(I2C_Speed);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  

//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	DELAY_Us(I2C_Speed);
	IIC_SCL=1; 
	IIC_SDA=1;//发送I2C总线结束信号
	DELAY_Us(I2C_Speed);	
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA=1;DELAY_Us(I2C_Speed);	   
	IIC_SCL=1;DELAY_Us(I2C_Speed);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>I2C_Speed)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 

//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	DELAY_Us(I2C_Speed);
	IIC_SCL=1;
	DELAY_Us(I2C_Speed);
	IIC_SCL=0;
}

//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	DELAY_Us(I2C_Speed);
	IIC_SCL=1;
	DELAY_Us(I2C_Speed);
	IIC_SCL=0;
}			

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
		SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {   
			IIC_SDA=(txd&0x80)>>7;
			txd<<=1; 	 
			DELAY_Us(I2C_Speed);
			IIC_SCL=1;
			DELAY_Us(I2C_Speed);   //对TEA5767这三个延时都是必须的
			IIC_SCL=0;
			DELAY_Us(I2C_Speed);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(void)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
  for(i=0;i<8;i++ )
	{
		IIC_SCL=0; 
		DELAY_Us(I2C_Speed);
		IIC_SCL=1;
		receive<<=1;
		if(READ_SDA) receive++;   
		DELAY_Us(I2C_Speed); 
	}					 

	IIC_Ack(); //发送ACK   
	return receive;
}


void XFS5152CE_IIC_WriteBytes(unsigned char* buf, int len)
{				   	  	    																 
	int i;  
	unsigned char t,ack;  
	
	IIC_Start();                        

	IIC_Send_Byte(0x80);
	IIC_Wait_Ack();
	
	for (i=0; i<len; i++)
	{	
		IIC_Send_Byte(buf[i]);
		IIC_Wait_Ack();
		IIC_SCL=0;
		DELAY_Us(I2C_Speed);   
	}
//	ack = XFS5152CE_IIC_ReadOneByte(addr);
	IIC_Stop();                     
}

u8 XFS5152CE_IIC_ReadOneByte(u8 addr)
{				  
	u8 temp=0;		  	    																 
	IIC_Start();  

	IIC_Send_Byte(addr);
	IIC_Wait_Ack();
  
	temp=IIC_Read_Byte();		   
	IIC_Stop();//产生一个停止条件	 
	u1_printf("temp read:0x%02x\n",temp);
	return temp;
}

void TTStest(void)
{
	int i = 0;
	unsigned char testBuf[13]={0xFD,  0x00,  0x0A,  0x01,  0x00,  0xBF,  
										0xC6,  0xB4,  0xF3,  0xD1,  0xB6,  0xB7,  0xC9};
	
	unsigned char volumeSet[7]={0xFD, 0x00, 0x04, 0x41, 0x01, 0x05, 0x01};

	XFS5152CE_IIC_WriteBytes(testBuf,13);
									
	u1_printf("tts test\n");
}

调试时,特别注意GPIO口模式配置,这里参考的是正点原子的STM32模拟i2c驱动进行修改实现的,调试过程中,使用到的示波器进行SCL和SDA两根数据线的时序进行分析判断,在GPIO控制输入输出寄存器的配置处,卡了好久,最终还是配置正确了,下面是SDA采用GPIOD_Pin15的输入输出寄存器配置。

#define SDA_IN()  {GPIOD->CRH&=0X0FFFFFFF;GPIOD->CRH|=8<<28;}
#define SDA_OUT() {GPIOD->CRH&=0X0FFFFFFF;GPIOD->CRH|=3<<28;}

配置寄存器之前,需要对这个寄存器进行查找其功能含义和配置工作方式:

查看STM32数据手册:

因为用到的是pin15,所以是GPIOx_CRH,如果用到时pin0~7,则需找GPIOx_CRL进行配置;MODE15的两位控制着GPIOD_Pin15的输入输出模式,通过对这两位进行位操作即可设置其输入输出工作模式。

参考I 2 C-bus specification and user manual文档,对I2C有一个较全面的了解,通信原理和收发过程,对上面代码的理解很有帮助。

 

 

 

 

 

 

 

 

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yzxjd1314

多谢鼓励,探索前行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值