I've been trying to set up 2 BGM13P32 on development boards with an I2C communication, where one would act as a master and the other one as a slave.
I did try to check what is the outcome on a Oscilloscope. I noticed that the integrated pull-ups are very weak and I did my own pull-ups just to see what would happen. The behavior stays the same but the signals are much more square.
Though, either the master keeps the SDA line low or the slave keeps the clock low for an indefinite amount of time after ACKing the address by the slave, which sometimes cause an Arbitration lost by the master and other times, it is just an undefined behavior of the I2C protocol.
Here is a code sample of what I have right now (yes it was taken from a few tutorials and forum questions because nothing was working as expected) :
static volatile bool transmitting = false;
void I2C0_IRQHandler(void)
{
uint32_t status = I2C0->IF;
if (status & I2C_IF_ADDR){ // Receiving Address
uint8_t addr;
addr = I2C0->RXDATA;
I2C_IntClear(I2C0, I2C_IFC_ADDR);
if (addr & 0x01) { // 0x01 is the read bit
I2C0->TXDATA = (uint32_t) tx_callback();
transmitting = true;
}
} else if (status & I2C_IF_RXDATAV) { // Receiving data
rx_callback(I2C0->RXDATA);
} else if (status & I2C_IF_ACK) { // Ack from master after first byte of data sent
if (transmitting) {
I2C0->TXDATA = (uint32_t) tx_callback();
}
I2C_IntClear(I2C0, I2C_IEN_ACK);
} else if (status & I2C_IF_NACK) { // Master Nack, stop sending data
if (transmitting) {
transmitting = false;
}
I2C_IntClear(I2C0, I2C_IFC_NACK);
}
if (status & I2C_IEN_SSTOP) { // Stop transfer
I2C_IntClear(I2C0, I2C_IFC_SSTOP);
}
}
void enableI2cSlaveInterrupts(void){
I2C_IntClear(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
I2C_IntEnable(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
NVIC_EnableIRQ(I2C0_IRQn);
}
void setup_i2c(bool is_master) {
// Set up SCL and SDA
I2C0->ROUTEPEN = I2C_ROUTEPEN_SCLPEN | I2C_ROUTEPEN_SDAPEN;
I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK)) | I2C_ROUTELOC0_SCLLOC_LOC15;
I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK)) | I2C_ROUTELOC0_SDALOC_LOC15;
// Remove PullUp configuration and add own pull-ups
GPIO_PinModeSet(BSP_I2C0_SCL_PORT, BSP_I2C0_SCL_PIN, gpioModeWiredAndPullUpFilter, 1);
GPIO_PinModeSet(BSP_I2C0_SDA_PORT, BSP_I2C0_SDA_PIN, gpioModeWiredAndPullUpFilter, 1);
if (is_master) {
for (unsigned int i = 0; i < 9; i++) {
GPIO_PinOutSet(BSP_I2C0_SCL_PORT, BSP_I2C0_SCL_PIN);
GPIO_PinOutClear(BSP_I2C0_SCL_PORT, BSP_I2C0_SCL_PIN);
}
}
I2C_Init_TypeDef i2c_configuration = I2C_INIT_DEFAULT;
i2c_configuration.master = is_master;
I2C_Init(I2C0, &i2c_configuration);
if (!is_master) {
I2C0->SADDR = SLAVE_ADDRESS;
I2C0->CTRL |= I2C_CTRL_SLAVE | I2C_CTRL_AUTOACK | I2C_CTRL_AUTOSN;
enableI2cSlaveInterrupts();
}
}
int main(void)
{
/* Initialize device */
initMcu();
/* Initialize board */
initBoard();
app_init();
setup_i2c(MASTER_NODE);
if (MASTER_NODE) {
printf("Master \n");
uint8_t data[1];
I2C_TransferSeq_TypeDef seq ={
.addr = SLAVE_ADDRESS,
.buf[0].data = data,
.buf[0].len = 1,
.flags = I2C_FLAG_READ
};
I2C_TransferReturn_TypeDef status;
status= I2C_TransferInit(I2C0, &seq);
while (status == i2cTransferInProgress){
status = I2C_Transfer(I2C0);
}
printf("Sent and received : %d with status : %d \n", seq.buf[0].data[0], status);
} else {
printf("Slave \n");
data_buffer[0] = 0x7F;
}
while (1) {
}
}
// In app_init()
CMU_ClockEnable(cmuClock_HFPER, true);
CMU_ClockEnable(cmuClock_GPIO, true);
CMU_ClockEnable(cmuClock_I2C0, true);
RETARGET_SerialInit();
It might be my configuration that is not adequate. At this point, I cannot figure out if it is a hardware or software problem.
Thank you for your time!
Bluetooth Low Energy
Discussion Forums
32-bit MCUs
Answered
Answered
Hi,
Your question is not Bluetooth related so it was moved to the 32-bit MCU forum.
Regards,
Tiago
0
addr = I2C0->RXDATA;
Shouldn't this be (since you are not sending any bytes after the address?)
addr = I2C0->SADDR;
Another post using I2C0 as a slave recommends setting the slave mask:
Add this line to the setupI2C function:
I2C0->SADDRMASK = 0x7F;
0
The slave address ( I2C0->SADDR ) is set during the setup. The slave does receive in it's RXDATA register the address when the master wants to communicate with one of his slave. I need to clear the RXDATA register before I can receive any more data.
I tried with the slave mask, but it didn't work. I am still receiving Arbitration loss.
0
This is from the EFR32xG1 reference:
17.3.9.3 Slave Transmitter
If the address was accepted and the R/W bit was set (R), indicating that the master wishes to read from the slave, the slave now goes into the slave transmitter mode. Software interaction is now required to decide whether the slave wants to acknowledge the request or not. The accepted address byte is loaded into the receive buffer like a regular data byte. If no valid interaction is pending, the bus is held until the slave responds with a command. The slave can reject the request with a single NACK command.
I don't see an ACK or NACK after you read RXDATA. Is this done in the tx_callback() ? Even if it is, an ACK/NACK is necessary if a write flag is received.
0
Correct me if I'm wrong, but isn't what I2C_CTRL_AUTOACK should do automatically?
I2C Undefined behavior - BGM13P32
Hello,
I've been trying to set up 2 BGM13P32 on development boards with an I2C communication, where one would act as a master and the other one as a slave.
I did try to check what is the outcome on a Oscilloscope. I noticed that the integrated pull-ups are very weak and I did my own pull-ups just to see what would happen. The behavior stays the same but the signals are much more square.
Though, either the master keeps the SDA line low or the slave keeps the clock low for an indefinite amount of time after ACKing the address by the slave, which sometimes cause an Arbitration lost by the master and other times, it is just an undefined behavior of the I2C protocol.
Here is a code sample of what I have right now (yes it was taken from a few tutorials and forum questions because nothing was working as expected) :
It might be my configuration that is not adequate. At this point, I cannot figure out if it is a hardware or software problem.
Thank you for your time!
Hi,
Your question is not Bluetooth related so it was moved to the 32-bit MCU forum.
Regards,
Tiago
Shouldn't this be (since you are not sending any bytes after the address?)
Another post using I2C0 as a slave recommends setting the slave mask:
The slave address ( I2C0->SADDR ) is set during the setup. The slave does receive in it's RXDATA register the address when the master wants to communicate with one of his slave. I need to clear the RXDATA register before I can receive any more data.
I tried with the slave mask, but it didn't work. I am still receiving Arbitration loss.
This is from the EFR32xG1 reference:
I don't see an ACK or NACK after you read RXDATA. Is this done in the tx_callback() ? Even if it is, an ACK/NACK is necessary if a write flag is received.
Correct me if I'm wrong, but isn't what I2C_CTRL_AUTOACK should do automatically?
I think it is already handled because I do catch an acknowledge on the master (I tried to put an interrupt and the flag was raised successfully)
It is still doing the same behavior when I try to force the command to acknowledge.
Thank you for your time.
(You are correct; I'm a novice when it comes to using the registers directly...)
Do you realize you are doing I2C_TransferInit twice?
Thank you so much! I actually never realized it...
For those wondering, I modified my first post to only give out the answer if somebody ever come across this code.