Trying to use Repeated Start I2C on STM32F103RCT6 but the MCU doesn't send a NACK at the end.
I am trying to communicate with a commonly used Accelerometer form NXP (MMA8451) which uses repeated start sequence over I2C protocol, which should look like this:
My problem is that the MCU doesn't seem to send a NACK at the end of transmission and may cause the communication to fail.
I am using I2C to DMA to read data form the accelerator and maybe the DMA has something to do with it?
This is what I am reading using a logic analyzer

and here is my code:
byte i2cBuff[8];
#define MMA845_ADDRESS 0x1C
#define MMA8451_REG_WHOAMI 0x1A
uint8_t MMA8451_readRegister(uint8_t reg) {
i2cBuff[0] = reg;
I2C_WriteOneByte(MMA845_ADDRESS,1,&i2cBuff,I2C_NO_STOP_CONDITION);
i2cBuff[1] = I2C_DMA_ReceiveData(MMA845_ADDRESS,1,I2C_START_CONDITION_YES);
return i2cBuff[1];
}
#include "common.h"
void I2C1_Init(void){
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
I2C2->CR2 |= 24; // APB1 Bus frequency in MHz
/* Set speed of 100kHz by
* this number is a division of I2C period(1/88kHz = 10us) by 2
* later divided by APB1 Bus period (1/24MHz = 41.6ns), which comes up to 135
* 1/88000kHz /
* ---------- / 1/24000000 = 135
* 2 / */
I2C1->CCR = 135; // speed 88kHz (standard mode,less than max due to Silicon limitations pointed out in Errata sheet PDF, higher freq avail in fast mode)
I2C1->TRISE = 15; //25; // (300ns / "CR2 period" (1/24MHz)) + 1 = TRISE
I2C1->CR1 |= I2C_CR1_ACK; // Enable ACKs
I2C1->CR1 |= I2C_CR1_POS;
// stretch mode enabled by default, nothing to do here
// 7 bit addressing mode enabled by default, nothing to do here
/* GPIO Init */
GPIO_InitTypeDef I2CPinsInit;
I2CPinsInit.Pin = GPIO_PIN_6 | GPIO_PIN_7;
I2CPinsInit.Mode = GPIO_MODE_AF_OD;
I2CPinsInit.Speed = GPIO_SPEED_FREQ_HIGH;
I2CPinsInit.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB,&I2CPinsInit);
I2C1->CR1 |= I2C_CR1_PE; // Enable the peripheral, needs to be done last
}
void I2C_WriteOneByte(uint8_t device_address,uint8_t len,uint8_t *data,i2c_condition_enum stop){
uint16_t temp;
I2C1->CR1 |= I2C_CR1_START; // generate start condition
while(!(I2C1->SR1 & I2C_SR1_SB)){
//do nothing until status register reads that Start condition was sent
}
I2C1->DR = (device_address << 1); // send 7 bit address shifted one bit to left to keep least significant bit for a read/write bit
while(!(I2C1->SR1 & I2C_SR1_ADDR)){
//do nothing until status register reads that there was a match for the address
}
temp = I2C1->SR2; //reading the Status register to clear a flag in SR1 (both SR1 and SR2 need to be read so this tricks it, to clear hardware flag)
for (int i = 0; i < len; ++i) {
I2C1->DR = data[i]; // data to be written in given address
while(!(I2C1->SR1 & I2C_SR1_TXE)){
// do nothing until the transfer is complete
}
len--;
}
if(stop == I2C_START_CONDITION_YES){
I2C1->CR1 |= I2C_CR1_STOP; // send STOP condition
}
}
uint8_t I2C_DMA_ReceiveData(uint8_t device_address,uint8_t len,i2c_condition_enum start){
uint16_t temp;
uint8_t data;
//DMA1 Request 7 for I2C1 RX
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
I2C1->CR2 |= I2C_CR2_DMAEN;
I2C1->CR1 |= I2C_CR1_ACK;
DMA1_Channel7->CMAR = (&data);
DMA1_Channel7->CPAR = (uint32_t)&I2C1->DR;
DMA1_Channel7->CNDTR = len;
DMA1_Channel7->CCR = DMA_CCR_TCIE | DMA_CCR_MINC | DMA_CCR_EN;
if(start == I2C_START_CONDITION_YES){
I2C1->CR1 |= I2C_CR1_START;
while(!(I2C1->SR1 & I2C_SR1_SB)){
//do nothing until status register reads that Start condition was sent
}
}
I2C1->DR = (device_address << 1) + 1; // send 7 bit address shifted one bit to left to keep least significant bit for a read/write bit, and add 1 for the read bit
while(!(I2C1->SR1 & I2C_SR1_ADDR)){
//do nothing until status register reads that there was a match for the address
}
temp = I2C1->SR2; //reading the Status register to clear a flag in SR1 (both SR1 and SR2 need to be read so this tricks it, to clear flag)
// HAL_Delay(2);
while((DMA1->ISR & DMA_ISR_TCIF7) == 0){
//Do nothing until the DMA transfer is complete
}
DMA1_Channel7 ->CCR &= ~(DMA_CCR_EN);
I2C1->CR1 |= I2C_CR1_STOP;
return data;
}
/**************************************************************************/
/*!
@brief Setups the HW (reads coefficients values, etc.)
*/
void main(void) {
I2C1_Init();
while(1){
HAL_delay(10);
MMA8451_readRegister(MMA8451_REG_WHOAMI);
}
}While there doesn't seem to be a problem, the MMA8451_readRegister() function is never allowed to repeat because it is stuck waiting for a
while(!(I2C1->SR1 & I2C_SR1_SB)) condition.
I don't know what am I doing wrong, when I use stops after starts the condition clears and the MMA8451_readRegister() is allowed to repeat.
I need to use repeated start to read the data from chip, but the flags don't clear.
