cancel
Showing results for 
Search instead for 
Did you mean: 

Alternate DMA I2C with normal operation

Martin van Es
Associate
Posted on June 04, 2018 at 15:59

I'm trying to rewrite the I2C gyro (MPU6050) read operation of an STM32F0xx based flight controller (

https://github.com/silver13/BoldClash-BWHOOP-B-03

) to partially TIM_Update/DMA based I2C readout for accurate looptime reasons (the project is NOT my work, I'm just trying to improve the codebase where possible).

This works, but only if I keep reading only the gyro and stick to DMA. For altitude hold however I want to read out the barometer in mainloop as well and hope to stay under TIM_Update refresh TIM_Period. What I did was generate a TIM_Update event, and in the TIM_Update interrupt handler, start a fresh I2C DMA read process for 14 bytes, and wait for DMA_TC. In DMA_TC handler I process the new gyro values and trigger mainloop.

The I2C hw readout lib that comes with the package guards for I2C jams by

https://github.com/silver13/BoldClash-BWHOOP-B-03/blob/ab84ed5bd7cfd0c117ecde60b1cc0972734e261f/Silverware/src/drv_hw_i2c.c&sharpL181

before commencing a new I2C read operation (in the i2c sendheader function that is shared with all i2c read operations).

The problem is: this works if I stick to non-DMA I2C and for DMA-only I2C, but as soon as gyro-DMA is done and I start a new

https://github.com/silver13/BoldClash-BWHOOP-B-03/blob/ab84ed5bd7cfd0c117ecde60b1cc0972734e261f/Silverware/src/drv_hw_i2c.c&sharpL260

for 1 byte I end up in an endless I2C_FLAG_BUSY loop that only ends because of a timeout.

I have tried every combination of disabling I2C DMA and clearing pending DMA TC/IC2 TC bits but nothing helps:

// Handle I2C TC

void DMA1_Channel2_3_IRQHandler(void)

{

DMA_ClearITPendingBit(DMA1_IT_TC3);

I2C_ClearITPendingBit(I2C1, I2C_IT_TCI);

DMA_ClearFlag( DMA1_FLAG_GL3 );

DMA_Cmd( DMA1_Channel3, DISABLE );

I2C_DMACmd( I2C1, I2C_DMAReq_Rx, DISABLE );

// RCC->APB1ENR |= (1UL << 21);

// I2C1->CR1 |= 0x8000;

// I2C1->CR1 &= (uint16_t) ~((uint16_t) 0x8000);

// while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == SET);

// while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) == RESET);

// while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == RESET);

// TIM_SetCounter( TIM17, 0 );

// TIM_Cmd( TIM17, ENABLE );

sixaxis_read(1); // 1 = DMA mainloop

// I2C_GenerateSTOP(I2C1, ENABLE);

liberror = 0;

i2c_readreg(0x76, 0x08); <- This 'normal' I2C read is pestered with I2C_FLAG_BUSY timeouts.

// mainloop();

// TIM_Cmd( TIM17, ENABLE );

}

liberror is supposed to be 0 all times, if it's nonzero, some sort of I2C BUSY/TC/TXE timeout has occured. I've inserted the liberror=0 for debug reasons, to prevent the code from bailing out on i2c problems and to have it available just before i2c_readreg while it contains last iteration errors.

The DMA setup routine looks like this:

void TIM17_IRQHandler(void)

{

TIM_ClearITPendingBit( TIM17, TIM_IT_Update );

DMA1_Channel3->CNDTR = 14;

DMA_Cmd( DMA1_Channel3, ENABLE );

I2C_DMACmd( I2C1, I2C_DMAReq_Rx, ENABLE );

hw_i2c_sendheader(SOFTI2C_GYRO_ADDRESS, 59 , 1 );

//send restart + readaddress

I2C_TransferHandling(I2C1, (SOFTI2C_GYRO_ADDRESS)<<1 , 14, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);

}

As can be seen, DMA CNDTR is set to 14 and I2C_TransferHandling asks for 14 bytes. I expect everyting to be done on DMA TC and I2C bus to be available for anything if I disable DMA Channel3 and I2C_DMAReq_Rx?

As can be seen, the project is based on Std Periperal lib.

Hope there's enough information to start discussing the problem, if not please let me know.

I deliberately didn't include the DMA /I2C initialisation because they both work seperately. It's only the transition from DMA to normal that's not working?

#i2c-isues #dma
0 REPLIES 0