cancel
Showing results for 
Search instead for 
Did you mean: 

Bare Metal ADC on NUCLEO-H745ZI-Q

zirogravity
Associate II

Hello,

I am troubleshooting a similar problem as described in this post TM32H7 ADC Baremetal - Cannot get ADC module ready

I am using PF10 on ADC3 as it is already routed to the CN10 header. Intentionally ignoring CMSIS header/defines in the spirit of learning. Using the default RCC /64MHz HSI / clock and have basic uart functionality on usart3. Using CM4 and ignoring CM7.

Initializing as follows:

//Enable clock access to GPIOF
RCC->AHB4ENR |=GPIOFEN;

//Set PF10 mode to analog
//The reset state for the pins is analog mode
//GPIOF->MODER |=(1U<<20);
//GPIOF->MODER |=(1U<<21);

//Enable clock access to ADC
RCC->AHB4ENR |=ADC3EN;

//Set ADC Kernel Clock Source to Peripheral Clock
RCC->D3CCIPR &=~(1U<<16);
RCC->D3CCIPR |= (1U<<17);

//Reset the ADC peripheral
RCC->AHB4RSTR |= (1U<<24);
RCC->AHB4RSTR &=~(1U<<24);

//DISABLE THE ADC BEFORE CONFIGURATION
ADC3->CR &=~ADEN;
while(ADC3->CR & ADEN){};

//ADC channel pre-selection register
ADC3->PCSEL  |=(1U<<6);

//Set ADC Continous Conversion Mode
ADC3->CFGR |=(1U<<13);

//ADC Channel Sequence
//Channel 6 of ADC3 so we need ADC_SQR1: SQ[4:0]=6 =0b110
//Only one channel ADC_SQR1:  L[3:0]=0 (length 1)
ADC3->SQR1 &= ~(1U<<0);
ADC3->SQR1 |=  (1U<<7);
ADC3->SQR1 |=  (1U<<8);

//Set ADC Clock Mode
//00: CK_ADCx (x=1 to 23) (Asynchronous clock mode), generated at product level (refer to
//Section Reset and Clock Control (RCC))
//01: adc_sclk/1 (Synchronous clock mode).
//10: adc_sclk/2 (Synchronous clock mode)
//11: adc_sclk/4 (Synchronous clock mode)
ADC3_COMMON->CCR |=((1U<<16)|(1U<<17));

//Clear the Deep Power Down Bit
ADC3->CR &=~DEEPPWD;

//Enable the ADC VREG
ADC3->CR |= ADVREGEN;

//Wait for ADC LDO Ready Flag
while(!(ADC3->ISR & LDORDY));

//1. Clear the ADRDY bit in the ADC_ISR register by writing ‘1’
ADC3->ISR |=ISR_ADRDY;

//2. Set ADEN=1.
ADC3->CR |= ADEN;

//3. Wait until ADRDY=1 (ADRDY is set after the ADC startup time). 
while(!(ADC3->ISR & ISR_ADRDY)){};

//4. Clear the ADRDY bit in the ADC_ISR register by writing ‘1’ (optional).
//ADC3->ISR |=ISR_ADRDY;

 It appears that I get a single ADC reading on "reset" but nothing after that. I can GND or apply 3.3V on PF10 and report an ADC count value via uart.

Screenshot from 2024-11-26 18-02-05.png

My adc read function and from what I can tell EOC never gets set/reset after each read.

uint32_t adc_read(void){

	//RM0399 Rev 4 page 1034
	//Wait for conversion completion
	 while(!(ADC3->ISR & ISR_EOC)){};

	 //Wait for sequence completion
	 //while(!(ADC3->ISR & ISR_EOS));

	//Read converted results
	return (ADC3->DR);
}

I have tried various insertions of delays in the form of:

for(int i=0; i<10000;i++);

 in various section of the code per the RM but that does not seem to be it. My overall main() is:

uint32_t adc3_ch6_count;

int main(void){

	usart3_tx_init();

	pf10_adc_init();

	start_conversion(); //Start ADC Conversion ADC3->CR |=  ADSTART;
}

	while(1){

		//for (int i=0;i<10000;i++);
		adc3_ch6_count =adc_read();
		printf("\nADC3_CH6 Count: %lu\r", adc3_ch6_count);
		for(int i=0; i<10000;i++);

	}
}

 

4 REPLIES 4
zirogravity
Associate II

Hi,

I am just noticing that the LDORDY bit field is not shown in the SFR debug view for STM32CubeIDE. Bit 12 is being set correctly. This should be OK I suppose and unrelated to why my code does not get past a reset/single read?stm32LDORDYMarkUp.png

stm32LDORDYMarkUp2.png

krotti42
Associate III

Hello @zirogravity !

 

NOTE

You have written, you use the default RCC/PWR setup. So the peripheral kernel clock is 64MHz.

The maximum allowed frequency for the ADC's is 40MHz (VOS3), 60MHz (VOS2) and 160MHz (VOS1 and VOS0).  Have you changed the voltage scaling (VOS) to VOS1 with the power controller (PWR)? The default is VOS3.

 

 

 

ADC maximum allowed frequencyADC maximum allowed frequency

 

 

 

Hi @krotti42 ,

Thank you for this insight. I will have a look today, make some changes, and report back. Perhaps I misunderstood but I thought when CKMODE[1:0] is set to 01 or 11 the prescaler would be either 2 or 4 which gets further divided by 2 according to Figure 142 ADC Clock Scheme diagram. The information shared is very helpful and I will test out. I have not changed or set VOS at all.


Screenshot from 2024-11-28 08-02-52.png

zirogravity
Associate II

Hello,

I am still stuck on this as I navigate the PWR registers.

In the spirit of trying to operate ADC3 in VOS3 (default) seems like it should be possible so long as ADC clock is 40MHz or less. I set the HSI clock to 32MHz by enabling  HSIDIV to 2. I am not using any other clocks i.e. PLL etc... so I am not switching clocks and I dont believe I have to worry about peripheral clock gating but rather just selecting the correct ADC3 clock source i.e. adc_sclk vs adc_ker_clk_input.

From what I gather this will be further divided by 2 at the ADC level which is why I thought the default 64MHz HSI clock should be OK. So reducing the HSI to 32MHz has not changed the behavior I was seeing before.

The first initial sample samples OK on MCU reset but then my code gets stuck in the while loop below right after the very first sample coming out of reset. Do I actually need to enable interrupts or anything like that for the EOC to work? My understanding from the RM that ths ADC3 ISR EOC is a hardware generated interrupt thus I do not need to configure it maybe?

 

 

uint32_t adc_read(void){

	//printf("begin adc_read();\n\r");
	//RM0399 Rev 4 page 1034
	//Wait for conversion completion
	while(!(ADC3->ISR & ISR_EOC)){};

	 //Wait for sequence completion
	 //while(!(ADC3->ISR & ISR_EOS));

	//Read converted results
	return (ADC3->DR);
}