AnsweredAssumed Answered

I2C always reports "busy", SR2->BERR

Question asked by Philip Lane on May 30, 2018

I'm using an STM8L051F3 chip as slave and a STM32L476 as master, but the STM8L refuses to respond, it keeps reporting a SR2->BERR aka busy error.

 

I know the STM32 code is ok as I had two of them working on an I2C link without any problems, but when I use an STM8 as a slave it fails.

 

The clock and data lines look ok on a scope, nice and square. I have compared the signals from 32-32 and 32-8, in the 32-8 the "ACK" pulse remains high instead of being pulled low.

 

STM8L code pasted below

 

--- I2C setup : ---

void Init_I2C(void)
{
CLK->CKDIVR = 0; // sys clock /1
CLK->PCKENR1 |= 0x08; // enable I2C peripheral clk

 

// Init GPIO for I2C use
GPIOC->DDR |= 0x03; // Output mode
GPIOC->CR1 &= 0xFC; // Output with Open drain
GPIOC->CR2 |= 0x03; // Fast

 

// --- SET BEFORE PE = 1 ---
I2C1->TRISER = 2;

// Set the clock control register (CCR)
I2C1->CCRL = 0x50; // Provides an output clock of 100kHz...
I2C1->CCRH = (u8)0; // ...at 50% duty cycle

// Cannot change I2C1 parameters if it is not active !
I2C1->CR1 = 0x01; // Enable I2C peripheral
I2C1->CR2 = 0x04; // Enable I2C acknowledgement
I2C1->FREQR = 16; // Set I2C Freq value (16MHz)
I2C1->OARL = (SLAVE_ADDRESS << 1) ; // set slave address (put 0xA2 for the register dues to7bit address)
I2C1->OARH = 0x40; // Set 7bit address mode
I2C1->ITR = 0x07; // all I2C interrupt enable
}

 

--- Interrupt ---

@far @interrupt void I2C_Slave_check_event(void)
{
static u8 sr1;
static u8 sr2;
static u8 sr3;

// save the I2C registers configuration
sr1 = I2C1->SR1;
sr2 = I2C1->SR2;
sr3 = I2C1->SR3;

// Communication error?
if (sr2 & I2C_SR2_WUFH)
{
I2C1->CR2 |= I2C_CR2_STOP; // stop communication - release the lines
I2C1->SR2 = 0; // clear all error flags
}
else if (sr2 & I2C_SR2_OVR)
{
I2C1->CR2 |= I2C_CR2_STOP; // stop communication - release the lines
I2C1->SR2 = 0; // clear all error flags
}
else if (sr2 & I2C_SR2_BERR)
{

// ---- ALWAYS GET THIS FLAG SET ----
I2C1->CR2 |= I2C_CR2_STOP; // stop communication - release the lines
I2C1->SR2 = 0; // clear all error flags
}

// More bytes received ?
if ((sr1 & (I2C_SR1_RXNE | I2C_SR1_BTF)) == (I2C_SR1_RXNE | I2C_SR1_BTF))
{
I2C_byte_received(I2C1->DR);
}

// Byte received ?
if (sr1 & I2C_SR1_RXNE)
{
I2C_byte_received(I2C1->DR);
}

// NAK? (=end of slave transmit comm)
if (sr2 & I2C_SR2_AF)
{
I2C1->SR2 &= ~I2C_SR2_AF; // clear AF
I2C_transaction_end();
}

// Stop bit from Master (= end of slave receive comm)
if (sr1 & I2C_SR1_STOPF)
{
I2C1->CR2 |= I2C_CR2_ACK; // CR2 write to clear STOPF
I2C_transaction_end();
}

// Slave address matched (= Start Comm)
if (sr1 & I2C_SR1_ADDR)
{
I2C_transaction_begin();
}

// More bytes to transmit ?
if ((sr1 & (I2C_SR1_TXE | I2C_SR1_BTF)) == (I2C_SR1_TXE | I2C_SR1_BTF))
{
I2C1->DR = I2C_byte_write();
}

// Byte to transmit ?
if (sr1 & I2C_SR1_TXE)
{
I2C1->DR = I2C_byte_write();
}
}

Outcomes