MCU simulation IIC and SPI: debugging RTC (RX8010) and Flash (GD25Q128)

In response to development requirements, debug and simulate I2C and SPI on the single-chip microcomputer BA45F5260. The single-chip microcomputer is Hetai 8-bit special-purpose single-chip microcomputer, which is mainly used in smoke alarms. Due to the requirements of UL standard certification, this test board is mainly used for data collection in the certification process. At the same time, RTC and Flash are added for better time correspondence.

1. Simulation SPI

1.1 Debug GD25Q12 without special attention to the test items, the ID is read successfully, that is, there is no problem in communication

#ifdef SUPPORT_SPI


#define SPI_CLK(data) (SPI_CLK_PIN = data)
#define SPI_MISO() (((SPI_MISO_PIN & amp;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;
\t
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);
\t
return redata;
}

#endif

1.2 Simple test read and write

/**************************************************** *********************/
//Description: FlashReadID()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**************************************************** *********************/
static void FlashReadID(void)
{
uint16_t Id = 0;
\t
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\\
",Id);
}
else
{
printf("Read ID err\\
");
}
}


/**************************************************** *********************/
//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("\\
");
}

2. Simulate I2C

2.1 You need to pay attention to the address description in the specification. At the beginning, you see the device address 0x32. Directly write the read and write as follows

The actual address is 7bit, so ACK cannot be obtained.

After re-modifying the read and write commands, the ACK signal is normal

2.2 The main code reference is as follows

/********************************************** *************************/
//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();
\t
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; //Pull down the clock to start data transmission
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 output is set to 0, set to INPUT
I2cDelayUs(2);
IIC_1_SCL=1;
I2cDelayUs(2);

IIC_1_SDA_IN();
while(IIC_1_SDA) //Waiting for the response, that is, waiting for the slave device to pull SDA low
{
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;
\t
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 clock acquisition

#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) & amp;0x07)*10 + (DataBuf[Sec] & amp;0x0F);
pTime->Min = ((DataBuf[Min]>>4) & amp;0x07)*10 + (DataBuf[Min] & amp;0x0F);
pTime->Hour = ((DataBuf[Hour]>>4) & amp;0x03)*10 + (DataBuf[Hour] & amp;0x0F);
pTime->Days = ((DataBuf[Days]>>4) & amp;0x03)*10 + (DataBuf[Days] & amp;0x0F);
pTime->WeekDays = (DataBuf[WeekDays] & amp;0x07);
pTime->Month = ((DataBuf[Mon]>>4) & amp;0x01)*10 + (DataBuf[Mon] & amp;0x0F);
pTime->Year = ((DataBuf[Years]>>4) & amp;0x0F)*10 + (DataBuf[Years] & amp;0x0F);
}

/**************************************************** *********************/
//Description: DecToBcdConversion()
//Parameters:
//Return:
//Date:
//Author: quanwu.xu
/**************************************************** *********************/
void DecToBcdConversion(TimeApi* pTime, uint8_t* DataBuf)
{
DataBuf[Sec] = ((((pTime->Sec)/10) & amp;0x07)<<4) + (((pTime->Sec) ) & amp;0x0F);
DataBuf[Min] = ((((pTime->Min)/10) & amp;0x07)<<4) + (((pTime->Min) ) & amp;0x0F);
DataBuf[Hour] = ((((pTime->Hour)/10) & amp;0x03)<<4) + (((pTime->Hour) ) & amp;0x0F);
DataBuf[Days] = ((((pTime->Days)/10) & amp;0x03)<<4) + (((pTime->Days) ) & amp;0x0F);
DataBuf[WeekDays] = (pTime->WeekDays) &0x07;
DataBuf[Mon] = ((((pTime->Month)/10) & amp;0x01)<<4) + (((pTime->Month) ) & amp;0x0F);
DataBuf[Years] = ((((pTime->Year)/10) & amp;0x0F)<<4) + (((pTime->Year) ) & amp;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("\\
IIC:\\
");
//printf("%x, ", ReadBuf[2]);
//printf("%x, ", ReadBuf[1]);
//printf("%x\\
", ReadBuf[0]);

BcdToDecConversion(pTimeTag, ReadBuf);
printf("T>>%d:%d:%d\\
", pTimeTag->Hour, pTimeTag->Min, pTimeTag->Sec);

//DecToBcdConversion(pTimeTag, WriteBuf);
//printf("%x:%x:%x\\
\\
\\
", WriteBuf[2]|(ReadBuf[2] & amp;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();
}