EEVblog Electronics Community Forum
Electronics => Microcontrollers => Topic started by: Alex-lab on April 06, 2024, 07:48:21 pm
-
Hi,
I am trying to use stm32G4 Timer1 Break functionality.
Previously the same basic code was working fine on F103, F303 and F411, but with G431 I've got some weird behaviour.
The main cycle sequentially triggers TIM1->ADC->DMA->DMA interrupt->serial ... etc. Everything works as expected until the NVIC interrupt for BRK is enabled. After that, the cycle operates ok (serial data is coming), but ADC returns zeros for all three channels.
I am using Arduino and register defined peripherals.
Example is in attachment, the only difference is in un/commenting of two NVIC related lines.
Has anybody experienced similar issue? Any guess?
Thank you.
-
Better attach you full sketch. The only thing that can be concluded from your picture is that, yes, in the one it gets enabled and in the other it is not.
Are you sure timer 1 is not used by the Arduino framework? (I don't use the Arduino environment that much :) )
Give us more to work with, because now it is just a guessing game. Like for instance the board you are using. Is it home made or something from WeAct Studio like this one (https://nl.aliexpress.com/item/1005005303669884.html).
That kind of information allows us to test things ourselves when we have the same stuff.
-
Yes TIM1 is not in use by Arduino. The board is a self-made G431C8T6 adaptation for the blue-pill form-factor. Just Pin to pin traces. 8MHz crystal.
In the beginning of the code, ADCres array initiated by certain numbers (100,200,300), which are replaced by zeros, but not by a real ADC conversion result. This means that DMA works correctly, but ADC conversion result is 0x00. If ADC clock had been disabled, conversions would have never ended and DMA would not have triggered the interrupt and data would not have been sent by Serial. But everything is working, except the value of ADC...
In the figure above you can see that first value in the line is ADC->DR register which is zero as well. So the problem is somewhere there, but I am unable to imaging how this could be.
I suspected that it may be affected by GPIO de-initialisation, but, in that case ADC conversion values are not zeros, just oscillating around 0-2 (tested).
The NVIC_enable function do nothing more than just set corresponding ISER bits.
Thanks.
The sketch:
// in file "stm32g4xx_hal_conf_default.h" add #define HSE_VALUE 8000000UL
uint32_t u32_ADCres[3] = {100, 200, 300};
boolean b_senden = false;
HardwareSerial Serial1(PB7, PB6);
//HardwareSerial Serial1(PA10, PA9);
void setup() {
NVIC_SetPriority(DMA1_Channel1_IRQn, 14);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
// NVIC_SetPriority(TIM1_BRK_TIM15_IRQn, 15);
// NVIC_EnableIRQ(TIM1_BRK_TIM15_IRQn);
Serial1.begin(115200);
pinMode(PC13, OUTPUT); //ON-OFF LED
pinMode(PB3, OUTPUT);
RCC->AHB2ENR = 0xFFFFFFFF; //GPIOs, ADC12EN
RCC->AHB1ENR = 0xFFFFFFFF; //DMA1
RCC->APB2ENR = 0xFFFFFFFF;
RCC->CCIPR |= 0x10000000; //ADC12 clock input selector, PLLP 113.33MHz
ADC12_COMMON->CCR |= 0x00040000; // ADC divider 1/2 Fadc=56.67MHz
ADC1->CFGR |= 0x0543; //DMA request enabled, circular mode, TIM1-TRGO2 - start of conversion
ADC1->SQR1 = 0xC2042; //ch1, once. 0x000C2042; //L=3, (PA0-2 = CH1-3) in a sequence, ADC1.CH0 - is internally connected to Vssa
ADC1->SMPR1 = 0x0049; //6.5 cycles sampling time for ch0-2.
ADC1->CR = 0; //Clear DEEPPWD
ADC1->CR = (1 << 28); //ADVREGEN = 1
delayMicroseconds(1000);
ADC1->CR |= (1 << 31); //ADCCAL = 1
while (ADC1->CR & (1 << 31));
ADC1->CR |= 1; //ADEN = 1
delayMicroseconds(1000);
ADC1->CR |= (1 << 2); //ADSTART = 1, soft start of the conversion
delayMicroseconds(1000);
GPIOA->AFR[0] = 0x00000000; //Alternative functions: PA0-2 - ADC
GPIOA->AFR[1] = 0x00000666; //Alternative functions: PA8,PA9,PA10 - TIM1
GPIOA->MODER = 0x002A0FFF; //Pa8,PA9, PA10 - TIM1 pushpul, Pa0-Pa5 - anaolog inp (PA4-7 are from ADC2)
GPIOA->OSPEEDR = 0xFFFFFFFF;
GPIOB->AFR[0] = 0x77088000; //Alternative functions: PB6, PB7 - USART1, PB3,PB4 - GPIO
GPIOB->AFR[1] = 0x46660000; //Alternative functions: PB12,PB13,PB14,PB15 - TIM1
GPIOB->MODER = 0xAA54A544; //PB3,4,5,9 GPIO out
GPIOB->OSPEEDR = 0xFFFFFFFF;
TIM1->ARR = 850; //PWMARR; //Max value of pWM counter
TIM1->CR2 = 0x00500000; //ADC call on Update event - 2
TIM1->CCMR1 = 0x3838; //CH1 high out on upconting, low out downcounting, preloading
TIM1->CCMR2 = 0x0038; //CH3 high out on upconting, low out downcounting, preloading
TIM1->CCER = 0x0555; //CH1,3 output, CH2 - no output
TIM1->PSC = 0x0; //Prescaler = 1
TIM1->BDTR = 0x80C30; //Dead time 48 tics (667 nS), auto output, uotputs disconnected, BRK filter: 7-444nS, 8-667nS, 9-890nS, A-1112nS
TIM1->CCR1 = 0x200; //VAR. PWM width changeable value
TIM1->CCR2 = 0x1; //Start ADC signal
TIM1->CCR3 = 0x1; //CONST.
TIM1->DIER = 0x0080; //BRK interrupts enabled
TIM1->RCR = 0x1; //Only each second (1+1) event causes interruption
TIM1->BDTR |= 0x3000; //Enable break function, active - high level
TIM1->EGR |= TIM_EGR_UG; //Immediate load of registers
TIM1->CR1 = 0x0180; //autoreload preload, edge aligned, run disabled
TIM1->SR = 0; //reset TIMER1 interrupt flag
TIM1->CR1 |= 1; //start TIM
TIM1->BDTR |= 0xC000;
DMA1_Channel1->CMAR = (uint32_t) & (u32_ADCres); //Starting address of ADC conversion results array
DMA1_Channel1->CPAR = (uint32_t) & (ADC1->DR); //Address of ADC data register
DMA1_Channel1->CNDTR = 0x0003; //3 words to be moved
DMA1_Channel1->CCR = 0b0000101010100010; //MSIZE, PSIZE 32 bits each, mem inc, TCIE interrupt, no enable DMA
DMA1->IFCR = 0xFFFFFFFF;
DMAMUX1_Channel0->CCR |= 0x0005; //ADC1 as DMA request source
DMA1_Channel1->CCR |= 0x1; // enable DMA
__enable_irq();
}
void loop() {
if (b_senden) {
Serial1.print("ADC1_DR: ");
Serial1.print(ADC1->DR);
Serial1.print(" ADC1_PA0: ");
Serial1.print(u32_ADCres[0]);
Serial1.print(" ADC1_PA1: ");
Serial1.print(u32_ADCres[1]);
Serial1.print(" ADC1_PA2: ");
Serial1.println(u32_ADCres[2]);
b_senden = false;
}
delay(100);
digitalWrite(PC13, HIGH);
digitalWrite(PB3, HIGH);
delay(200);
digitalWrite(PC13, LOW);
delay(200);
digitalWrite(PB3, LOW);
}
extern "C" void DMA1_Channel1_IRQHandler(void) { //happens when DMA obtain data from ADC
b_senden = true;
DMA1->IFCR = 0xFFFFFFFF; //Clear interrupt status bit
}
extern "C" void TIM1_BRK_TIM15_IRQHandler() { //
TIM1->BDTR &= ~0xC000; //OFF PWM outputs
TIM1->CR1 &= ~0x0001; //Disable counter
TIM1->SR = 0x0000;
}
extern "C" void SystemClock_Config(void) //HSE, Fclk = 170MHz, Fadc = 56.67MHz
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
/** Initializes the RCC Oscillators according to the specified parameters
in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; //RCC_OSCILLATORTYPE_HSI48|
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
// RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
RCC_OscInitStruct.PLL.PLLN = 85;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV3;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC->PLLCFGR |= (1 << 16); //PLLP enable
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
// HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_16); //PA8 - 10.625MHz x16 = 170MHz
}
-
Further investigation revealed that the issue comes from the ADC clock settings.
In order to get maximum performance, SYSCLK was set to 170MHz. ADC clock Fadc was supplied from PLL P-out (113.33MHz) divided by ADC divider (1/2) yielding ~56MHz (<60 fadc_max).
However, this configuration fails when TIM1_BRK IRQ enabled. But, when I switched ADC input to SYSCLK (instead of PLLP) the ADC conversion occurred, even though the Fadc was 170/2 = 85MHz, more than specified maximum of 60MHz!
May be I misunderstand the maximum ratings?
I have checked MCO frequency of SYSCLK - it's ok, 170M...
-
I don't write anything about it in EErdata datasheet?
-
Sorry, it was a stupid mistake |O
Manual says:
1. Clear the ADRDY bit in the ADC_ISR register by writing 1.
2. Set ADEN.
3. Wait until ADRDY = 1
I just set ADEN and waited for 1 ms, but this was not enough...