2018-09-19 10:22 AM
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:
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
}
}
}
2018-09-19 04:01 PM
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 ?
2018-09-19 06:22 PM
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
2018-09-19 10:55 PM
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?
2018-09-24 02:13 AM
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