如何解决使用I2C数据的具有DMA RX的STM32L011K4没有出现在缓冲区中
已解决:DMA的CPAR和CMAR寄存器并不意味着我最初相信的含义。 CMAR是DMA应在其中放置数据的存储位置的大小(在这种情况下,L011K4的每个存储位置均为32位)。 CPAR是外设的大小,与I2C从设备的寄存器不同。外设是I2C RX数据寄存器,因此必须将其设置为8位。
数据现在正常显示在缓冲区中。第一个字节传输在buf [0],第二个字节传输在buf [1]。
我正在尝试使用L011K4的DMA控制器通过I2C总线查询温度传感器(TMP007)。我设法使TMP007响应良好的数据,但是该数据没有出现在通过I2C DMA接收功能的缓冲区阵列中。
我希望发生的是,通过Init和Read功能中的软件设置了I2C硬件,然后生成了启动条件,发送了从站的地址和寄存器地址,然后进行了第二次启动/重启发送,然后再次发送从站的地址,最后以从TMP007发送两个字节和停止条件结束。
从温度传感器获取的数据应该出现在传递给Start_Read的缓冲区中(作为MemoryBaseAddress),但是在调用read函数后在调试模式下查看处理器时,该数据不会出现
正在调用通道3传输完成中断 ,因此我知道DMA已激活并管理了RX传输,但是数据没有出现在所需的缓冲区中。
以下是逻辑分析仪正在观察的通信的图像:https://i.imgur.com/SzySsXl.png DIO2连接到板载LED,它告诉我们DMA传输已完成(这是唯一具有LED切换的ISR)。
任何帮助将不胜感激!
STM32L011K4参考手册:https://www.st.com/resource/en/reference_manual/dm00108282-ultralowpower-stm32l0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
void I2C1_DMA_Start_Read(int SlaveAddress,int RegisterAddress,int* MemoryBaseAddress,int BufferSize) {
I2C1->CR1 &= ~I2C_CR1_PE; // Disable I2C1
DMA1_Channel3->CCR &= ~DMA_CCR_EN; // Disable Channel 3 DMA
DMA1_Channel3->CCR &= ~(0x00007FFF); // Channel 3 DMA mask
// Configure DMA Channel 3 for 16 bit memory and peripheral,and other aliased settings (reference manual page 249,10.4.3)
DMA1_Channel3->CCR |= (0b11 << 12)|(0b01 << 10)|(0b01 << 8)|DMA_CCR_MINC|DMA_CCR_TEIE|DMA_CCR_TCIE;
DMA1_Channel3->CPAR = (uint32_t) &(I2C1->RXDR);
DMA1_Channel3->CMAR = (uint32_t) MemoryBaseAddress;
DMA1_Channel3->CNDTR = (uint16_t) BufferSize;
DMA1_Channel3->CCR |= DMA_CCR_EN; // Activate DMA channel 3
I2C1->CR1 |= I2C_CR1_NACKIE; // Enable no acknowledge interrupt for I2C1
I2C1->CR2 |= ((uint8_t) (SlaveAddress << 1)); // Set up the slave address
I2C1->CR2 &= ~I2C_CR2_RD_WRN; // Master requests a write transfer in order to send the register
I2C1->CR1 |= I2C_CR1_PE|I2C_CR1_RXDMAEN; // Enable I2C1 and RX DMA for I2C1
I2C1->CR2 &= ~(0xFF << I2C_CR2_NBYTES_Pos); // Mask byte count
I2C1->CR2 |= (0x01 << I2C_CR2_NBYTES_Pos); // Transfer one byte (the slave's register address)
while(!(I2C1->ISR & I2C_ISR_TXE)); // Wait until TX data register is empty
I2C1->TXDR = RegisterAddress; // Set the transmit data to the desired register address
I2C1->CR2 |= I2C_CR2_START; // Generate start condition
while(I2C1->CR2 & I2C_CR2_START); // Wait until hardware clears the start bit
while(!(I2C1->ISR & I2C_ISR_TC)); // Wait until hardware clears the transmit complete bit
I2C1->CR2 |= I2C_CR2_RD_WRN; // Master requests a read transfer after sending over the register address
I2C1->CR2 &= ~(0xFF << I2C_CR2_NBYTES_Pos); // Mask byte count
I2C1->CR2 |= (0x02 << I2C_CR2_NBYTES_Pos); // Master looks for two bytes from the slave
I2C1->CR2 |= I2C_CR2_START; // Generate start condition
while(I2C1->CR2 & I2C_CR2_START); // Wait until hardware clears the start bit
return;
}
void DMA1_Channel2_3_IRQHandler() {
if(DMA1->ISR & DMA_ISR_TCIF3) {
GPIOB->ODR ^= 1 << 3; // Toggle the onboard LED as an indicator
I2C1->CR2 |= I2C_CR2_STOP; // Generate stop condition
while(I2C1->CR2 & I2C_CR2_STOP); // Wait until hardware clears the stop bit
DMA1->IFCR |= DMA_IFCR_CTCIF3; // Clear transfer complete interrupt bit
I2C1->CR1 &= ~I2C_CR1_PE; // Disable I2C1
DMA1_Channel3->CCR &= ~DMA_CCR_EN; // Disable Channel 3 DMA
} else if(DMA1->ISR & DMA_ISR_TEIF3) {
I2C1->CR2 |= I2C_CR2_STOP; // Generate stop condition (if I2C comm is already stopped on error,delete this and following line)
while(I2C1->CR2 & I2C_CR2_STOP); // Wait until hardware clears the stop bit
DMA1->IFCR |= DMA_IFCR_CTEIF3; // Clear transfer error interrupt bit
I2C1->CR1 &= ~I2C_CR1_PE; // Disable I2C1
DMA1_Channel3->CCR &= ~DMA_CCR_EN; // Disable Channel 3 DMA
}
return;
}
void I2C1_IRQHandler() {
if(I2C1->ISR & I2C_ISR_NACKF) {
//GPIOB->ODR ^= 1 << 3; // Toggle the onboard LED as an indicator
I2C1->ICR |= I2C_ICR_NACKCF;
}
return;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。