cancel
Showing results for 
Search instead for 
Did you mean: 

IIC Slave causing issue

Scott Dev
Senior

Hi

I am using a STM32L433 IIC port as a slave. I am connecting it to another processor which has been used without any issues on another project so I know the connecting processor works fine as IIC master.

I simply have set the processor up to simply send back a packet when requested. The process is as follows:

  1. External CPU send 2 bytes of data which consists of values 23 and 14 . 23 is a header, 14 a command indicating on the next read request the STM32 will send back 24 bytes.
  2. After No.1 the CPU send a read request for 24 bytes.

A simple test which works fine , the 2 processors communicates for a while before stopping . I placed a logic analyser on the IIC and it looks like my processor is stretching the clock. I have attached 3 snap shots. One being the whole capture, the other 2 being the start and end.

There is nothing else on the IIC port, and is pulled up with 3.3k resistors (I also have tried 10k), and distance is quite short between both. The master device is setup for 100KHz communication, and I have set mine up also to 100KHz, but tried it at 400KHz too. My processor is running at 16MHz which the IIC is running from. Below is a snapshot of some of my code, and totally baffled of what can be the issue. If someone have any ideas , it would be much appreciated.

regards

Scott

Setup:

void SetupI2C(void)

{

  //I am using 2 IIC ports, IIC1 and IIC2, IIC2 is the one I am using,

   RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;

   RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;

  

   RCC->APB1ENR1 |= RCC_APB1ENR1_I2C2EN;//Enable the I2C #2

   I2C2->CR1 &= ~I2C_CR1_PE; //disable peripherable 2

   RCC->CCIPR &= ~RCC_CCIPR_I2C2SEL;

   RCC->CCIPR |= RCC_CCIPR_I2C2SEL_0;

   //mode,type,speed and alternate function

   //Mode Register set for alternate function, PB10 (SCK) PB11 (SDA)

   GPIOB->MODER &= ~GPIO_MODER_MODE10;

   GPIOB->MODER |= GPIO_MODER_MODE10_1;

   GPIOB->MODER &= ~GPIO_MODER_MODE11;

   GPIOB->MODER |= GPIO_MODER_MODE11_1;

   //Type Register Open drain

   GPIOB->OTYPER |= GPIO_OTYPER_OT_10;

   GPIOB->OTYPER |= GPIO_OTYPER_OT_11;

   //output speed register high

   GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR10;

   GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR11;

   GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10;

   GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR11;

   //No internal pull up, pull down resistors

   GPIOB->PUPDR &= ~GPIO_PUPDR_PUPD10;

   GPIOB->PUPDR &= ~GPIO_PUPDR_PUPD11;

   //set alternate function AF4

   GPIOB->AFR[1] &= ~GPIO_AFRH_AFSEL10;

   GPIOB->AFR[1] |= (0x4 << 8);//AF4

   GPIOB->AFR[1] &= ~GPIO_AFRH_AFSEL11;

   GPIOB->AFR[1] |= (0x4 << 12);//AF4

   I2C2->OAR1 |=( 19<<1); //set slave address to 19

   I2C2->CR1 |= I2C_CR1_GCEN; //enable General call

   I2C2->CR1 |= I2C_CR1_SBC;

    I2C2->CR2 |= I2C_CR2_RELOAD;

   I2C2->CR2 |= (1<<16); //load NBYTES to 1.

   I2C2->OAR1 |=0x8000; //Enable OA1, 7Bit address mode

   I2C2->CR2 |= I2C_CR2_AUTOEND;

   Buff=I2C2->RXDR;

   I2C2->ISR |= 1; //flush TX

   I2C2->ICR |=I2C_ICR_ADDRCF;

   I2C2->ICR |=I2C_ICR_NACKCF;

   I2C2->CR1 |= I2C_CR1_ADDRIE; //enable peripherable enable I

   I2C2->CR1 |= I2C_CR1_RXIE; //enable peripherable enable I

   I2C2->CR1 |= I2C_CR1_NACKIE; //enable peripherable enable I

   NVIC_SetPriority(I2C2_EV_IRQn,1);

    NVIC_EnableIRQ(I2C2_EV_IRQn);

//////////////////////////////

   //Set to 400KHz. see p1046 Ref Manual

   I2C2->TIMINGR |= 0x9;  //SCLL

   I2C2->TIMINGR |= (0x3<<8); //SCLH

   I2C2->TIMINGR |= (0x2 <<16); //SDADEL

   I2C2->TIMINGR |= (0x3 << 20); //SCLDEL

   I2C2->TIMINGR |= (0x1 << 28); //PRESC

  

   I2C2->CR1 |= I2C_CR1_PE; //enable peripherable enable

}

interupt:

void I2C2_EV_IRQHandler(void)

{

   //set if address matches

   if(I2C2->ISR & I2C_ISR_ADDR_Msk)

   {

      //get direction

      if(I2C2->ISR & I2C_ISR_DIR_Msk )

      { //transmit 24 bytes

         I2C2->CR2 &= ~I2C_CR2_NBYTES_Msk;

         I2C2->CR2 |= (24<<16); //load NBYTES .

         I2C2->CR2 &= ~I2C_CR2_RELOAD;

         I2C2->ISR |= 1; //flush TX

         I2C2->CR1 |= I2C_CR1_TXIE; //start TX

      }

      I2C2->ICR |= I2C_ICR_ADDRCF; //clear address flag

   }

   //received an nack

   if(I2C2->ISR & I2C_ISR_NACKF_Msk)

      I2C2->ICR |= I2C_ICR_NACKCF;

   //data waiting to be read

   if(I2C2->ISR & I2C_ISR_RXNE)

   {

       ReadByte=I2C2->RXDR; //read in byte

   .. do some work with info into a buffer and set I2C_Slave.RxComplete if need to

      I2C_Slave.Rx[I2C_Slave.RxPtr++]=ReadByte;

      if(!I2C_Slave.RxComplete) //if read all bytes

      { //no

            I2C2->CR2 &= ~I2C_CR2_NBYTES_Msk; //set to 1 byte to read

            I2C2->CR2 |= (1<<16); //load NBYTES to 1.

            I2C2->CR2 |= I2C_CR2_RELOAD;

      }

      else

      {

         I2C2->CR2 &= ~I2C_CR2_RELOAD; //all data read, so clear reload

         I2C_Slave.RxComplete=1; //set flag to read in complete

      }

   }

   else//transmit mode,

   if(I2C2->ISR & I2C_ISR_TXIS)

   {

         I2C2->TXDR=I2C_Slave.Tx[I2C_Slave.TxPtr++]; //transmit byte

         if(!--I2C_Slave.TxCount) //all 24 bytes sent?

         { //yes

            I2C2->CR1 &= ~I2C_CR1_TXIE; //disable TX interupt

            I2C_Slave.TxComplete=1; //mark complete

         }

   }

}

4 REPLIES 4
T J
Lead

this looks like an issue,

Clive has always complained about Read Modify Write...

      I2C2->CR1 &= ~I2C_CR1_TXIE; //disable TX interupt

there can be a time where the contents have been read, something else has changed before it is written, thereby losing some bit of data sometimes..

@Community member​ , what is the best method of Read modify write ?

RMW is an issue on the TIM->SR register, where it is designed to AND on write. I don't think it's and issue with IC2->CR1

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Scott Dev
Senior

I will have to keep the TIM->SR in mid when I come to use it. As there is nothing else on the bus, and no other part of the application using these registers apart from the interupt routine, I assume RMW cant be an issue here? As the processor I am talking to is working perfect on another project, I am stuck on thinking what to do. When I stop the debug at this point, I can see the BUSY flag is set. If I try to reset the IIC port , by calling the SetupIIC() above , the BUSY flag doesnt clear, why is this?

Scott Dev
Senior

I managed to find the issue. As I was using A/D interupts, this was causing issues with the IIC interupt. After changing the priority to a higher value on the IIC, i dont have any issues now. I have been running it for a few days now, communicating every second , without any problems. Im still a newbie to the STM32 (previous processor didnt have interupt priorities), and still learning 🙂

Scott