应开发需求,在单片机BA45F5260调试模拟I2C和SPI。该单片机为合泰8位专用型单片机,主要应用于烟雾报警器。因UL标准认证需求,本测试板主要用于认证过程数据收集,同时为了更好的时间对应关系,固增加RTC和Flash。
一、模拟SPI
1.1 调试GD25Q12无特别注意试项,读取ID成功,即通信无问题
#ifdef SUPPORT_SPI
#define SPI_CLK(data) (SPI_CLK_PIN = data)
#define SPI_MISO() (((SPI_MISO_PIN&0x01)==0x01)?1:0)
#define SPI_MOSI(data) (SPI_MOSI_PIN = data)
/**********************************************************************/
//Name: SpiDelayUs()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
static void SpiDelayUs(uint8_t Cnt)
{
while (Cnt--);
}
/**********************************************************************/
//Name: SpiReadWriteByte()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
uint8_t SpiReadWriteByte(uint8_t data)
{
uint8_t i;
uint8_t redata = 0;
for(i=0;i<8;i++)
{
SPI_CLK(0);
SpiDelayUs(5);
if(data & 0x80)
{
SPI_MOSI(1);
}
else
{
SPI_MOSI(0);
}
data <<= 1;
SPI_CLK(1);
SpiDelayUs(5);
redata<<=1;
if(SPI_MISO())
{
redata++;
}
}
SPI_CLK(0);
return redata;
}
#endif
1.2 简单测试读写
/**********************************************************************/
//Description: FlashReadID()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
static void FlashReadID(void)
{
uint16_t Id = 0;
SPI_CHIP_SEL();
SpiReadWriteByte(DRV_SPI_FLASH_READ_DEVICE_ID);
SpiReadWriteByte(0x00);
SpiReadWriteByte(0x00);
SpiReadWriteByte(0x00);
Id = SpiReadWriteByte(0x00)<<8;
Id += SpiReadWriteByte(0x00);
SPI_CHIP_NSEL();
if(Id == GD25Q128_DEVICE_ID)
{
printf("Device_ID:%x\r\n",Id);
}
else
{
printf("Read ID err\n");
}
}
/**********************************************************************/
//Description: FlashWriteNoCheck()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void FlashWriteNoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t Length)
{
uint16_t PageRemainBytes = PAGE_MAX_BYTES - WriteAddr%PAGE_MAX_BYTES; //the page remain bytes
if(Length<=PageRemainBytes)
{
PageRemainBytes = Length;
}
while(1)
{
FlashWritePage(pBuffer, WriteAddr, PageRemainBytes);
if(Length == PageRemainBytes)
{
break;
}
else
{
pBuffer += PageRemainBytes;
WriteAddr+= PageRemainBytes;
Length -= PageRemainBytes;
if(Length > PAGE_MAX_BYTES)
{
PageRemainBytes = PAGE_MAX_BYTES;
}
else
{
PageRemainBytes = Length;
}
}
}
}
/**********************************************************************/
//Description: FlashReadByte()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void FlashReadByte(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t Length)
{
GlobalIntDisable();
SPI_CHIP_SEL();
SpiReadWriteByte(DRV_SPI_FLASH_READ_DATA); //Fast Read CMD
SpiReadWriteByte((uint8_t)(ReadAddr>>16)); //24 bits Addr
SpiReadWriteByte((uint8_t)(ReadAddr>>8));
SpiReadWriteByte((uint8_t)(ReadAddr));
while (Length--)
{
*pBuffer = SpiReadWriteByte(0x00);
pBuffer++;
}
SPI_CHIP_NSEL();
GlobalIntEnable();
}
/**********************************************************************/
//Description: FlashInit()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void FlashInit(void)
{
uint8_t i = 0;
uint8_t TestBuf[4] ={'1', '3', '5', '7'};
uint8_t Read[4] = {0};
FlashReadID();
//FlashEraseChip();
//FlashEraseSector(0);
FlashWriteNoCheck(TestBuf, 2, 4);
FlashReadByte(Read, 2, 4);
for(i=0; i<4; i++)
{
printf("%x ", Read[i]);
}
printf("\n");
}
二、模拟I2C
2.1 需要注意规格书地址描述,一开始看到设备地址0x32。直接将读写写成如下
实际地址是7bit,固得不到ACK。
固重新修改读写命令后,ACK信号正常
2.2 主要代码参考如下
/**********************************************************************/
//Name: I2cDelayUs()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
static void I2cDelayUs(uint8_t Cnt)
{
while(Cnt--);
GCC_DELAY(5);
}
/**********************************************************************/
//Name: I2c1Init()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void I2c1Init(void)
{
IIC_1_SCL_OUT();
IIC_1_SDA_OUT();
IIC_1_SCL = 0;
IIC_1_SDA = 0;
}
/**********************************************************************/
//Name: I2c1DeInit()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void I2c1DeInit(void)
{
IIC_1_SCL_OUT();
IIC_1_SDA_OUT();
IIC_1_SCL = 0;
IIC_1_SDA = 0;
}
/**********************************************************************/
//Name: I2c1Start()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void I2c1Start(void)
{
IIC_1_SDA_OUT();
IIC_1_SDA=1;
I2cDelayUs(2);
IIC_1_SCL=1;
I2cDelayUs(2);
IIC_1_SDA=0;
I2cDelayUs(2);
IIC_1_SCL=0;
I2cDelayUs(2);
}
/**********************************************************************/
//Name: I2c1Stop()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void I2c1Stop(void)
{
IIC_1_SDA_OUT();
IIC_1_SDA=0;
I2cDelayUs(2);
IIC_1_SCL=1;
I2cDelayUs(2);
IIC_1_SDA=1;
I2cDelayUs(2);
}
/**********************************************************************/
//Name: I2c1Ack()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void I2c1Ack(void)
{
IIC_1_SCL=0;
IIC_1_SDA_OUT();
IIC_1_SDA=0;
I2cDelayUs(2);
IIC_1_SCL=1;
I2cDelayUs(2);
IIC_1_SCL=0;
}
/**********************************************************************/
//Name: I2C1NAck()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void I2C1NAck(void)
{
IIC_1_SCL=0;
IIC_1_SDA_OUT();
IIC_1_SDA=1;
I2cDelayUs(2);
IIC_1_SCL=1;
I2cDelayUs(2);
IIC_1_SCL=0;
}
/**********************************************************************/
//Name: I2c1SendByte()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
Res I2c1SendByte(uint8_t Data)
{
uint8_t t = 0;
uint8_t ucErrTime = 0;
IIC_1_SDA_OUT();
IIC_1_SCL=0; //拉低时钟开始数据传输
for(t=0;t<8;t++)
{
if(Data&0x80)
{
IIC_1_SDA=1;
}
else
{
IIC_1_SDA=0;
}
Data<<=1;
I2cDelayUs(2);
IIC_1_SCL=1;
I2cDelayUs(2);
IIC_1_SCL=0;
}
IIC_1_SDA=0; //SDA输出置0,设为INPUT
I2cDelayUs(2);
IIC_1_SCL=1;
I2cDelayUs(2);
IIC_1_SDA_IN();
while(IIC_1_SDA) //等待应答,也就是等待从设备把SDA拉低
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_1_SCL=0;
return FAIL;
}
}
IIC_1_SCL=0;
return OK;
}
/**********************************************************************/
//Name: I2c1ReadByte()
//Description:
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
uint8_t I2c1ReadByte(void)
{
uint8_t i=0, Data=0;
IIC_1_SDA_IN();
I2cDelayUs(2);
for(i=0;i<8;i++)
{
IIC_1_SCL=1;
I2cDelayUs(2);
Data<<=1;
Data|=IIC_1_SDA;
I2cDelayUs(2);
IIC_1_SCL=0;
I2cDelayUs(2);
}
return Data;
}
RX8010时钟获取
#define RX8010_ADDR 0x32
#define RX8010_ADDR_W ((RX8010_ADDR<<1)&0xFE)
#define RX8010_ADDR_R ((RX8010_ADDR<<1)|0x01)
#define RX8010_REG_WATCH_SEC 0x10
#define RX8010_REG_WATCH_MIN 0x11
#define RX8010_REG_WATCH_HOUR 0x12
#define RX8010_REG_WATCH_WEEK 0x13
#define RX8010_REG_WATCH_DAY 0x14
#define RX8010_REG_WATCH_MON 0x15
#define RX8010_REG_WATCH_YEAR 0x16
/**********************************************************************/
//Description: Bm8563Init()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void RX8010Init(void)
{
pTimeTag->Sec = 0;
pTimeTag->Min = 0;
pTimeTag->Hour = 0;
pTimeTag->Days = 0;
pTimeTag->WeekDays = 0;
pTimeTag->Month = 0;
pTimeTag->Year = 0;
GetRX8010Data();
}
/**********************************************************************/
//Description: BcdFormatConversion()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void BcdToDecConversion(TimeApi* pTime, uint8_t* DataBuf)
{
pTime->Sec = ((DataBuf[Sec]>>4)&0x07)*10 + (DataBuf[Sec]&0x0F);
pTime->Min = ((DataBuf[Min]>>4)&0x07)*10 + (DataBuf[Min]&0x0F);
pTime->Hour = ((DataBuf[Hour]>>4)&0x03)*10 + (DataBuf[Hour]&0x0F);
pTime->Days = ((DataBuf[Days]>>4)&0x03)*10 + (DataBuf[Days]&0x0F);
pTime->WeekDays = (DataBuf[WeekDays]&0x07);
pTime->Month = ((DataBuf[Mon]>>4)&0x01)*10 + (DataBuf[Mon]&0x0F);
pTime->Year = ((DataBuf[Years]>>4)&0x0F)*10 + (DataBuf[Years]&0x0F);
}
/**********************************************************************/
//Description: DecToBcdConversion()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void DecToBcdConversion(TimeApi* pTime, uint8_t* DataBuf)
{
DataBuf[Sec] = ((((pTime->Sec)/10)&0x07)<<4) + (((pTime->Sec)%10)&0x0F);
DataBuf[Min] = ((((pTime->Min)/10)&0x07)<<4) + (((pTime->Min)%10)&0x0F);
DataBuf[Hour] = ((((pTime->Hour)/10)&0x03)<<4) + (((pTime->Hour)%10)&0x0F);
DataBuf[Days] = ((((pTime->Days)/10)&0x03)<<4) + (((pTime->Days)%10)&0x0F);
DataBuf[WeekDays] = (pTime->WeekDays)&0x07;
DataBuf[Mon] = ((((pTime->Month)/10)&0x01)<<4) + (((pTime->Month)%10)&0x0F);
DataBuf[Years] = ((((pTime->Year)/10)&0x0F)<<4) + (((pTime->Year)%10)&0x0F);
}
/**********************************************************************/
//Description: Bm8563Init()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void GetRX8010Data(void)
{
uint8_t i = 0;
uint8_t ReadBuf[BUF_LENGTH] = {0};
//uint8_t WriteBuf[BUF_LENGTH] = {0};
//1、start
I2c1Start();
//2、write addr
I2c1SendByte(RX8010_ADDR_W);
//3、write data reg
I2c1SendByte(RX8010_REG_WATCH_SEC);
//4、start
I2c1Start();
//5、read addr reg
I2c1SendByte(RX8010_ADDR_R);
//6、read data
GCC_DELAY(1000);
for(i=0; i<BUF_LENGTH; i++)
{
ReadBuf[i]=I2c1ReadByte();
if(i == (BUF_LENGTH-1))
{
I2C1NAck();
}
else
{
I2c1Ack();
}
GCC_DELAY(100);
}
//7、stop
I2c1Stop();
//printf("\nIIC:\n");
//printf("%x, ", ReadBuf[2]);
//printf("%x, ", ReadBuf[1]);
//printf("%x\n", ReadBuf[0]);
BcdToDecConversion(pTimeTag, ReadBuf);
printf("T>>%d:%d:%d\n", pTimeTag->Hour, pTimeTag->Min, pTimeTag->Sec);
//DecToBcdConversion(pTimeTag, WriteBuf);
//printf("%x:%x:%x\n\n\n", WriteBuf[2]|(ReadBuf[2]&0xC0), WriteBuf[1]|(ReadBuf[1]&0x80), WriteBuf[0]|(ReadBuf[0]&0x80));
}
/**********************************************************************/
//Description: Bm8563Init()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**********************************************************************/
void SetRX8010Data(TimeApi* pTime)
{
uint8_t i = 0;
uint8_t WriteBuf[BUF_LENGTH] = {0};
DecToBcdConversion(pTime, WriteBuf);
//1、start
I2c1Start();
//2、write addr
I2c1SendByte(RX8010_ADDR_W);
//3、write data reg
I2c1SendByte(RX8010_REG_WATCH_SEC);
//4、Write Data
GCC_DELAY(1000);
for(i=0; i<BUF_LENGTH; i++)
{
I2c1SendByte(WriteBuf[i]);
}
//5、stop
I2c1Stop();
}