STM32 I2C 只传输一次

Posted

技术标签:

【中文标题】STM32 I2C 只传输一次【英文标题】:STM32 I2C Only Transmits Once 【发布时间】:2021-12-27 22:26:07 【问题描述】:

我使用 stm32f3 Datasheet 作为寄存器级编程的参考,而不是 HAL。我很确定我正确设置了所有内容,因为我实际上能够通过 I2C 外围设备传输数据字节但是当我将从地址更改为不同的设备(从加速度计到磁力计)时它无法发送字节我得到一个 NACK和停止条件。为什么会这样?

这是我的时钟设置:

void ResetClockControl() 

RCC->CFGR |= RCC_CFGR_SW_PLL|RCC_CFGR_HPRE_DIV1|RCC_CFGR_PPRE1_DIV2|RCC_CFGR_PPRE2_DIV1
        |RCC_CFGR_PLLSRC_HSE_PREDIV|RCC_CFGR_PLLXTPRE_HSE_PREDIV_DIV1|RCC_CFGR_PLLMUL6|RCC_CFGR_MCO_NOCLOCK;
RCC->CR &= ~(RCC_CR_HSION);                                                                                                                             //Turn off HSI
RCC->CSR &= ~(RCC_CSR_LSION);                                                                                                                           //Turn off LSI

/* Set bit PLLON last and wait until it is locked */
RCC->CR |= RCC_CR_HSEON|RCC_CR_HSEBYP|RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));

这是我的 I2C 初始化函数(也初始化从寄存器设置):

void I2C_Init() 
/* Peripheral Clock Enable */
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;         //Enable clock to I2C
RCC->AHBENR |= RCC_AHBENR_GPIOBEN|RCC_AHBENR_DMA1EN; // GPIO/DMA Init
RCC->CFGR3 |= RCC_CFGR3_I2C1SW_SYSCLK; //Set SYSCLK as source

/* GPIO Configuration */
GPIOB->MODER |= GPIO_MODER_MODER6_1|GPIO_MODER_MODER7_1;//alternate function
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6|GPIO_OSPEEDER_OSPEEDR7;
GPIOB->OTYPER |= GPIO_OTYPER_OT_6|GPIO_OTYPER_OT_7;  //open drain
GPIOB->PUPDR |= GPIO_PUPDR_PUPDR6_0|GPIO_PUPDR_PUPDR7_0; // pulllup
GPIOB->AFR[0] |= 0x04000000|0x40000000; ; //AF for SCL and SDA no bit values in 
header...

/* Configure DMA Rx */
DMA1_Channel7->CNDTR |= 0x0006; //6 bytes of acc/mag data to be transferred
DMA1_Channel7->CPAR = (uint32_t)&I2C1->RXDR;//0x40005424 I2C receive register address
DMA1_Channel7->CMAR = (uint32_t)test; // DMA memory address to write to
DMA1_Channel7->CCR |= DMA_CCR_EN|DMA_CCR_CIRC|DMA_CCR_MINC|DMA_CCR_TCIE; //memory 
increase, interrupt is not enabled assumed to be completed. Circular mode


/* I2c Configuration */
I2C1->TIMINGR |= 0x2010091A; //400KHz fast mode generated from cubeMX
I2C1->CR1 |= I2C_CR1_PE|I2C_CR1_RXDMAEN;// DMA Rx Enable

/* LSM303AGR_Init(); */
uint8_t Data[2] = 0;
Data[0]= 0x20;
Data[1]= 0x57;
I2C_WriteByte(0x19<<1,Data);
Data[0]= 0x23;
Data[1]= 0x20;
I2C_WriteByte(0x19<<1,Data);
Data[0]= 0x60;
Data[1]= 0x0C;
I2C_WriteByte(0x1E<<1,Data);
Data[0]= 0x62;
Data[1]= 0x10;
I2C_WriteByte(0x1E<<1,Data);


void I2C_WriteByte(uint8_t sAddress,uint8_t* sData) 

I2C1->CR2 |= 0x02<<I2C_CR2_NBYTES_Pos|sAddress; //NbyteToWrite,slave address,Read/Write
I2C1->CR2 |= I2C_CR2_START; //Start I2C transfer
while(!(I2C1->ISR & I2C_ISR_TXIS)) //wait until ready to send byte
I2C1->TXDR = sData[0]; //sub reg
while(!(I2C1->ISR & I2C_ISR_TXIS)) //wait until ready to send byte
I2C1->TXDR = sData[1]; //data
I2C1->CR2 |= I2C_CR2_STOP;
I2C1->ICR |= I2C_ICR_STOPCF;

这两个函数是从 main 调用的。首先调用 ResetClockControl。

另外,定时寄存器的值是CubeMX生成的(正的我这里设置的cubeMX和时钟参数一样)

谁能找出这里的问题?

谢谢

【问题讨论】:

【参考方案1】:

不确定为什么会这样,但在我切换到 I2C 总线上的另一个从设备之前,我需要将我打算发送的字节数重置为 0。我在 2 个从设备传输之间使用这条线来执行此操作:

I2C1->CR2 = 0x00

我在数据表中找不到任何地方说我必须在切换从设备之前重置 NBYTES 或任何其他重置 NBYTES 的原因,但这似乎对我有用。

【讨论】:

以上是关于STM32 I2C 只传输一次的主要内容,如果未能解决你的问题,请参考以下文章

Stm32F2xx与arduino之间的I2C通信

spidma发送更新中断

STM32F1HAL库的I2C应用注意事项

i2c 传输,stm32f103 作为 Master,STOP 条件生成问题

带有 DMA 的 STM32 I2C 传输已完成,但 DMA 中断程序不工作

I2C 通信中的问题 - STM32(HAL 库)