cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F030C8T6 DMA I2C stuck in endless while loop without interrupt

table
Associate II

Hi.

I tried using DMA with I2C before using interrupts and I seem to get the same problem that still remains unsolved.
This time around I decided I will try and not use any interrupts to make things a bit simple. However I am still getting the same result and I just can not seem to figure out why my I2C coms get stuck in the middle of a transmission. The Error flag is not going up either.

I am trying to read from the 0x0C (raw_angle) address from a AS5600 IC.
I do this by sending '0x0C' to '0x36'(AS5600 address). On the BusPirate on SNIFFER mode I see the following on the bus line.
[0x6C+
This did not change from the last example. When I take the BusPirate and the AS5600 IC alone and run the command Step1: [0x6C 0x0C]
Step2: [0x6D rr]
I do manage to get some legit bytes referring to what I believe is the raw_angle values.

When I put it all back onto the MCU it just gets stuck WITH OR WITHOUT the BusPirate on the bus.
In the code below the breakpoint will get stuck in the while loop on line 86 " while (!(DMA1->ISR & DMA_ISR_TCIF2)){} // Wait for DMA transfer complete "

I just do not know what I am doing wrong here.

#include <stdint.h> #include "stm32f030x8.h" #if !defined(__SOFT_FP__) && defined(__ARM_FP) #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use." #endif void Clock_Setup(void) { RCC->CR |= RCC_CR_HSION; // Enable High-Speed Internal Clock while (!(RCC->CR & RCC_CR_HSIRDY)); // Wait for HSI to stabilize RCC->CFGR &= ~RCC_CFGR_SW; // Set HSI as SYSCLK RCC->CFGR |= RCC_CFGR_SW_HSI; while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); RCC->CFGR &= ~RCC_CFGR_HPRE; // AHB Prescaler: Divide by 1 RCC->CFGR &= ~RCC_CFGR_PPRE; // APB Prescaler: Divide by 1 } void Config_Pin13(){ // Set PC13 as output GPIOC->MODER &= ~(3U << (13 * 2)); // Clear MODER13[1:0] GPIOC->MODER |= (1U << (13 * 2)); // Set MODER13[1:0] to 01 (General-purpose output mode) } void I2C_DMA_Init(void) { // Enable clocks for I2C1, DMA, GPIOB RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Enable DMA clock RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // Enable I2C1 clock RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // Enable GPIOB clock // Configure GPIOB pins for I2C1 (PB6: SCL, PB7: SDA) GPIOB->MODER &= ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7); // Clear mode GPIOB->MODER |= (GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1); // Set to Alternate Function GPIOB->AFR[0] |= (1 << GPIO_AFRL_AFRL6_Pos) | (1 << GPIO_AFRL_AFRL7_Pos); // AF1 for I2C1 GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7; // Open-drain GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6 | GPIO_OSPEEDER_OSPEEDR7; // High speed GPIOB->PUPDR |= GPIO_PUPDR_PUPDR6_0 | GPIO_PUPDR_PUPDR7_0; // Pull-up // Configure I2C1 I2C1->TIMINGR = 0x20000913; // Configure timing for 8 MHz HSI and 100 kHz I2C I2C1->CR1 = I2C_CR1_PE; // Enable I2C1 // Configure DMA for I2C1 // TX DMA (I2C1_TX -> Memory to Peripheral) DMA1_Channel2->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // Memory increment, Read from memory DMA1_Channel2->CPAR = (uint32_t)&I2C1->TXDR; // Peripheral address // RX DMA (I2C1_RX -> Peripheral to Memory) DMA1_Channel3->CCR = DMA_CCR_MINC | DMA_CCR_TCIE; // Memory increment DMA1_Channel3->CPAR = (uint32_t)&I2C1->RXDR; // Peripheral address I2C1->CR1 |= (I2C_CR1_RXDMAEN | I2C_CR1_TXDMAEN); } void I2C_Read_DMA(uint8_t deviceAddr, uint8_t *data, uint16_t size) { // Configure DMA for RX DMA1_Channel3->CNDTR = size; // Number of bytes to transfer DMA1_Channel3->CMAR = (uint32_t)data; // Memory address DMA1_Channel3->CCR |= DMA_CCR_EN; // Enable DMA channel // Start I2C transfer I2C1->CR2 = (deviceAddr << 1) | (size << 16) | I2C_CR2_RD_WRN | I2C_CR2_START; // Set address, size, read mode, and start condition // Wait for transfer to complete while (!(DMA1->ISR & DMA_ISR_TCIF3)); // Wait for DMA transfer complete DMA1->IFCR = DMA_IFCR_CTCIF3; // Clear transfer complete flag // Wait for STOP condition while (!(I2C1->ISR & I2C_ISR_STOPF)); I2C1->ICR = I2C_ICR_STOPCF; // Clear STOP flag // Disable DMA channel DMA1_Channel3->CCR &= ~DMA_CCR_EN; } void I2C_Write_DMA(uint8_t deviceAddr, uint8_t *data, uint16_t size) { // Configure DMA for TX DMA1_Channel2->CNDTR = size; // Number of bytes to transfer DMA1_Channel2->CMAR = (uint32_t)data; // Memory address DMA1_Channel2->CCR |= DMA_CCR_EN; // Enable DMA channel // Start I2C transfer I2C1->CR2 = (deviceAddr << 1) | (size << 16) | I2C_CR2_START; // Set address, size, and start condition // Wait for transfer to complete while (!(DMA1->ISR & DMA_ISR_TCIF2)){} // Wait for DMA transfer complete DMA1->IFCR = DMA_IFCR_CTCIF2; // Clear transfer complete flag // Wait for STOP condition while (!(I2C1->ISR & I2C_ISR_STOPF)); I2C1->ICR = I2C_ICR_STOPCF; // Clear STOP flag // Disable DMA channel DMA1_Channel2->CCR &= ~DMA_CCR_EN; } int main(void) { uint32_t counter_1 = 0; uint32_t counter_2 = 0; uint8_t txData[] = {0x0C}; uint8_t rxData[2]; Clock_Setup(); // Configure the clock Config_Pin13(); I2C_DMA_Init(); I2C_Write_DMA(0x36, txData, 1); I2C_Read_DMA(0x36, rxData, 2); while (1) { counter_1++; if (counter_1 == 10000) { counter_1 = 0; counter_2++; if (counter_2==10){ counter_2=0; GPIOC->ODR ^= (1U << 13); I2C_Write_DMA(0x36, txData, 1); } } } }
View more

 

 

10 REPLIES 10
STea
ST Employee

Hello @table ,

may I ask for the reason you are using direct access to registers making it difficult to identify if it was done the right way as DMA config especially requires specific sequence described in Reference manual. using HAL will make it much easier to develop and debug and for such application the cost on memory footprint is negligible unless this is a requirement i recommend you use HAL or LL library which will help us in the debug process and return values of it functions to know for sure what is not correctly implemented.
Regards

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
table
Associate II

Hello @STea 

 

I Generally do not use HAL because of vendor lock in.
I use various vendors of MCUs.

 

Thanks.

gbm
Principal

GPIOC is not enabled in your code. STM32 I2C is quite complex when compared to other vendors. The sequence of events and software actions in I2C routines is not that simple. Start with HAL for I2C. Also, DMA for I2C is rarely a good solution - I2C is slow by its nature, so interrupt-based service is reasonable.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

@table wrote:

I Generally do not use HAL because of vendor lock in.


Even you are not using HAL try to inspire from it. At least it will be a good starting point.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
table
Associate II

So I enabled GPIOC by enabling the clock for it before setting anything else for PortC?
"RCC->AHBENR |= RCC_AHBENR_GPIOCEN;"

Also the I2C is on GPIOB right? So the GPIOC has to be enabled non the less?

 

Thanks

I just want to get this version working and then I will look into HAL.

 

Thanks

The idea is to inspire from it not forcing you to use it and to speed up your development.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
table
Associate II

Hi @gbm 

 

I tried enabling it in line 31 on the code shown above.
I basically added this -> "RCC->AHBENR |= RCC_AHBENR_GPIOCEN".
However it is still doing the same.
When I activate the BusPirate pull ups it gives me this on the sniffer before getting stuck.
[0x6C-[]

This is odd because I am under the impression that the port pulls ups are switched on via software.

 

Thanks

gbm
Principal

Config_Pin13 doesn't config anything if GPIOC is disabled - that's your case. I'm not an expert when it comes to STM32 I2C but I suspect your I2C code is incorrect - it looks much too simple for STM32. ;)

Have you checked the basic I2C operation without DMA?

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice