Это конфигурация I2 C со всеми связанными конфигурациями DMA, при использовании в качестве подчиненного передатчика I2 C указатель для i2c1_output_FIFO не сбрасывается, даже если я отключаю соответствующий канал, когда отправляется NACK для последнего байта указатель, который использует DMA, должен быть сброшен, в моем случае это не так. Любое решение?
Поскольку это ведомое устройство, DMA не знает заранее размер передачи. В серии F4 DMA можно установить в режим периферийной синхронизации, а когда канал отключен, это сигнализирует об окончании передачи, как это делается в серии F1.
В этом коде в i2c1_output_FIFO предварительно загружены некоторые значения отладки, чтобы вернуть некоторые данные обратно. Это также часть I2 C для более крупной программы, и вся конфигурация I2 C происходит в этом программном сегменте, поэтому проблема, вероятно, будет в ЭТОМ разделе.
I2 C сам по себе работает, как и ожидалось, это просто указатели DMA, которые не сбрасываются при отключении канала DMA.
#include "main.h"
volatile uint8_t i2c1_output_FIFO[64]; // data that is actually going to be sent out
volatile uint8_t i2c1_input_FIFO[64]; // data that is read
volatile uint8_t i2c1_output_buffer[64]; // data to be loaded into the output buffer
volatile _Bool stop_enable;
volatile _Bool ack_fail;
void I2C1_init() {
// I2C1 TX DMA - DMA1, Channel 6
// I2C1 RX DMA - DMA1, Channel 7
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // enable I2C1 clock, 36 MHz input clock
RCC->AHBENR |= RCC_AHBENR_DMA1EN; // enable DMA1 clock
// Channel 6 for transmitted data
DMA1_Channel6->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; //increment memory, memory-to-peripheral transfer, enable transfer completion interrupt
DMA1_Channel6->CPAR = (uint32_t)(&I2C1->DR); // set peripheral address
DMA1_Channel6->CMAR = (uint32_t)(&i2c1_output_FIFO); // set memory address to the sample output structure
// Channel 7 for received data
DMA1_Channel7->CCR |= DMA_CCR_MINC | DMA_CCR_TCIE; //increment memory, peripheral-to-memory transfer, enable transfer completion interrupt
DMA1_Channel7->CPAR = (uint32_t)(&I2C1->DR); // set peripheral address to the I2C data register
DMA1_Channel7->CMAR = (uint32_t)(&i2c1_input_FIFO); // set memory
i2c1_output_FIFO[0] = 0xB8;
i2c1_output_FIFO[1] = 0xC2;
i2c1_output_FIFO[2] = 0xC3;
i2c1_output_FIFO[3] = 0xC4;
i2c1_output_FIFO[4] = 0xC5;
i2c1_output_FIFO[5] = 0xC6;
i2c1_output_FIFO[6] = 0xC7;
i2c1_output_FIFO[7] = 0xC8;
I2C1->OAR1 |= (0x75<<1); // set 0x75 as the slave address
I2C1->CR2 |= (36<<I2C_CR2_FREQ_Pos) | I2C_CR2_DMAEN | I2C_CR2_ITERREN | I2C_CR2_ITEVTEN; // set up input clock, enable DMA, error interrupt enable
I2C1->CCR |= I2C_CCR_FS | (30<<0); // Fast mode, set up for 400 KHz
I2C1->TRISE = 35;
I2C1->CR1 |= I2C_CR1_PE | I2C_CR1_ACK; // enable peripheral, enable acknowledge
}
uint8_t I2C1_start(uint8_t slave_address, uint8_t rw) {
ack_fail = 0;
I2C1->CR1 |= I2C_CR1_START; // generate start condition
while(((I2C1->SR1>>I2C_SR1_SB_Pos)&1) == 0) { // wait for start condition to be completed
}
I2C1->DR = slave_address<<1 | rw; // load slave address and RW bit
while(((I2C1->SR1>>I2C_SR1_ADDR_Pos)&1) == 0) { // wait for address to be transmitted
}
I2C1->SR2; // read status register 2 to clear ADDR flag
return (I2C1->SR1>>I2C_SR1_AF_Pos) & 1; // return 1 if NACK was received
}
void I2C1_stop() {
I2C1->CR1 |= I2C_CR1_STOP; // generate stop condition
}
void I2C1_transfer_TX(uint8_t slave_address, uint8_t byte_num, uint8_t stop_) { // main function to write data via DMA
I2C1_start(slave_address, 0); // generate start condition, send slave address and RW bit
if(ack_fail == 0) {
for(uint16_t i=0; i<byte_num; i++) {
i2c1_output_FIFO[i] = i2c1_output_buffer[i]; // transfer data over to the output buffer
}
stop_enable = stop_; // set up the stop enable flag
DMA1_Channel6->CNDTR = byte_num; // set up DMA to transfer a certain number of bytes
DMA1_Channel6->CCR |= DMA_CCR_EN; // start writing data from the output FIFO that was set up
}
else {
if(stop_ == 1)
I2C1_stop();
}
}
void I2C1_transfer_RX(uint8_t slave_address, uint8_t byte_num, uint8_t stop_) { // main function to receive data via DMA
I2C1_start(slave_address, 1); // generate start condition, send slave address and RW bit
if(ack_fail == 0) {
stop_enable = stop_; // set up the stop enable flag
I2C1->CR2 |= I2C_CR2_LAST; // last byte is at the end of transfer
DMA1_Channel7->CNDTR = byte_num; // set up DMA to transfer a certain number of bytes
DMA1_Channel7->CCR |= DMA_CCR_EN; // start writing data from the output FIFO that was set up
}
else {
if(stop_ == 1)
I2C1_stop();
}
}
void I2C1_ER_IRQHandler() {
if(((I2C1->SR1>>I2C_SR1_AF_Pos)&1)==1 && ((I2C1->SR2>>I2C_SR2_MSL_Pos)&1) == 1) { // if acknowledge failure was detected... (Master Mode)
I2C1->SR1 &= ~I2C_SR1_AF; // clear ack fail bit
// terminate transfer
DMA1_Channel6->CCR &= ~DMA_CCR_EN; // disable DMA channel to end transfer (Causes end of transfer interrupt)
ack_fail = 1;
}
}
void I2C1_EV_IRQHandler() { // Slave Configuration
uint16_t temp1 = I2C1->SR1;
uint16_t temp2 = I2C1->SR2;
if(((temp2>>I2C_SR2_MSL_Pos)&1) == 0) { // if in slave mode...
if(((temp1>>I2C_SR1_ADDR_Pos)&1) == 1) { //and address was received...
if(((temp2>>I2C_SR2_TRA_Pos)&1)==0) { // if in slave receiver mode...
DMA1_Channel7->CNDTR = 64;
DMA1_Channel7->CCR |= DMA_CCR_EN; // start sending received data to the input FIFO
}
else if (((temp2>>I2C_SR2_TRA_Pos)&1)==1) { // if in slave transmitter mode...
I2C1->SR1 &= ~I2C_SR1_AF; // write a 0 to the AF bit in SR1
DMA1_Channel6->CNDTR = 64;
DMA1_Channel6->CCR |= DMA_CCR_EN; // start writing data from the output FIFO that was set up
}
}
if(((temp1>>I2C_SR1_STOPF_Pos)&1) == 1) {
DMA1_Channel7->CCR &= ~DMA_CCR_EN; // disable DMA channel to end transfer
DMA1->IFCR |= DMA_IFCR_CTCIF7; // clear interrupt flag
}
if(((temp1>>I2C_SR1_AF_Pos)&1) == 1) { // end of slave transmission
I2C1->SR1 &= ~I2C_SR1_AF; // write a 0 to the AF bit in SR1
DMA1_Channel6->CCR &= ~DMA_CCR_EN; // disable DMA channel to end transfer
DMA1->IFCR |= DMA_IFCR_CTCIF6; // clear interrupt flag
GPIOB->ODR |= (1<<0);
}
}
}
void DMA1_Channel6_IRQHandler() { // Transfer complete ISR (TX)
DMA1->IFCR |= DMA_IFCR_CTCIF6; // clear interrupt flag
DMA1_Channel6->CCR &= ~DMA_CCR_EN; // disable DMA channel to end transfer
//DMA1_Channel6->CCR |= DMA_CCR_PFCTRL; // Slave Configuration, enable peripheral control
while(((I2C1->SR1>>I2C_SR1_BTF_Pos) & 1) == 0) {}
if(stop_enable == 1) {
stop_enable = 0;
I2C1_stop();
}
}
void DMA1_Channel7_IRQHandler() { // Transfer complete ISR (RX)
DMA1->IFCR |= DMA_IFCR_CTCIF7; // clear interrupt flag
DMA1_Channel7->CCR &= ~DMA_CCR_EN; // disable DMA channel to end transfer
//DMA1_Channel7->CCR |= DMA_CCR_PFCTRL; // Slave Configuration, enable peripheral control
if(stop_enable == 1) {
stop_enable = 0;
I2C1_stop();
}
}