#c #embedded #stm32 #i2c #dma
#c #встроенный #stm32 #i2c #dma
Вопрос:
Я пытаюсь запросить датчик температуры (TMP007) по шине I2C, используя контроллер DMA L011K4. Мне удалось заставить TMP007 отвечать хорошими данными, но эти данные не отображаются в буферном массиве, который я передаю своей функции приема I2C DMA.
Я ожидаю, что аппаратное обеспечение I2C настраивается программным обеспечением в функции инициализации и чтения, затем генерируется условие запуска, отправляются адрес ведомого устройства и адрес регистра, затем отправляется второй запуск / перезапуск, за которым снова следует адрес ведомого устройства, и, наконец,завершается передачей двух байтов из TMP007 и условием остановки.
Данные, полученные от датчика температуры, должны отображаться в буфере, который передается в Start_Read (как MemoryBaseAddress), но эти данные не отображаются при просмотре процессора в режиме отладки после вызова функции чтения.
Вызывается прерывание завершения передачи по каналу 3, поэтому я знаю, что DMA активировал и управлял передачей RX, но данные не отображаются в нужном буфере.
Вот изображение связи, наблюдаемой логическим анализатором: https://i.imgur.com/SzySsXl.png DIO2 подключен к встроенному светодиоду, который сообщает нам, что передача DMA завершена (это единственный ISR со светодиодным переключателем).
Любая помощь будет высоко оценена!
Спецификация STM32L011K4: https://www.st.com/content/ccc/resource/technical/document/datasheet/42/c0/ab/e5/71/7a/47/0b/DM00206508.pdf/files/DM00206508.pdf/jcr:content/translations/en.DM00206508.pdf
Справочное руководство по 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 amp;= ~I2C_CR1_PE; // Disable I2C1
DMA1_Channel3->CCR amp;= ~DMA_CCR_EN; // Disable Channel 3 DMA
DMA1_Channel3->CCR amp;= ~(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) amp;(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 amp;= ~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 amp;= ~(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 amp; 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 amp; I2C_CR2_START); // Wait until hardware clears the start bit
while(!(I2C1->ISR amp; 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 amp;= ~(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 amp; I2C_CR2_START); // Wait until hardware clears the start bit
return;
}
void DMA1_Channel2_3_IRQHandler() {
if(DMA1->ISR amp; 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 amp; I2C_CR2_STOP); // Wait until hardware clears the stop bit
DMA1->IFCR |= DMA_IFCR_CTCIF3; // Clear transfer complete interrupt bit
I2C1->CR1 amp;= ~I2C_CR1_PE; // Disable I2C1
DMA1_Channel3->CCR amp;= ~DMA_CCR_EN; // Disable Channel 3 DMA
} else if(DMA1->ISR amp; 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 amp; I2C_CR2_STOP); // Wait until hardware clears the stop bit
DMA1->IFCR |= DMA_IFCR_CTEIF3; // Clear transfer error interrupt bit
I2C1->CR1 amp;= ~I2C_CR1_PE; // Disable I2C1
DMA1_Channel3->CCR amp;= ~DMA_CCR_EN; // Disable Channel 3 DMA
}
return;
}
void I2C1_IRQHandler() {
if(I2C1->ISR amp; I2C_ISR_NACKF) {
//GPIOB->ODR ^= 1 << 3; // Toggle the onboard LED as an indicator
I2C1->ICR |= I2C_ICR_NACKCF;
}
return;
}
Комментарии:
1.
if(magic_numbers == USED) then expext_no_help();
2. Приносим извинения за то, что не включили таблицы данных. Я удалил магические числа, которые можно было заменить макросом stm32. Некоторые значения были взяты прямо из справочного руководства l011k4, поэтому я их не трогал.