Skip to main content
adaniel
Associate III
December 21, 2020
Question

ADC calibration problem for Stm32CubeIde?

  • December 21, 2020
  • 8 replies
  • 3863 views

 Chip:   STM32L030

 Trying to calibrate the ADC at startup with the following code into the initialization procedure:

   ADC1->CR |= 0X80000000;      // calibration started

   while (!(ADC1->ISR & 0X800));   // waiting for the calibration to finish

 When compiled with Atollic, version 9.2.0, this code works perfectly. But when compiled with Stm32CubeIde, it gets trapped into the calibration command which never finish!

This topic has been closed for replies.

8 replies

TDK
Super User
December 22, 2020

EOCAL is set at the end of the calibration. You're waiting until it's set. This is a race condition. So either the loop will immediately pass (if calibration isn't done yet), or it will never exit.

This is a software bug, not a CubeIDE issue.

0693W000006Gd98QAC.png

"If you feel a post has answered your question, please click ""Accept as Solution""."
adaniel
adanielAuthor
Associate III
December 22, 2020

This is exactly what my code does! If it is not a CubeIDE issue, how do you explain that Atollic 9.2.0 compiles successfully?

TDK
Super User
December 22, 2020
Yeah, you're right. I misread what was going on at first.
Still think it's a software bug, but you didn't include much of the code. It could also be a silicon bug that may be addressed in an errata.
STM32CubeIDE uses the GCC compiler under the hood which is quite mature. Unlikely the compiler is the issue. The IDE is just the UI. You could examine the assembly instructions that each one of them generates if you wanted to investigate that lead further.
"If you feel a post has answered your question, please click ""Accept as Solution""."
Piranha
Principal III
December 24, 2020

> Chip:   STM32L030

There is no such chip...

Use code tags when posting code. And use the readable CMSIS defined bit field names.

if (ADC1->CR & 1) ADC1->CR |= 2; // ADC setup
 ADC1->CR |= 0X80000000; // ADC calibration started
 while (!(ADC1->ISR & 0X800)) { // waiting for the calibration to finish
 watchdog(); // macro to refresh the watchdog
 if (!--n) return FALSE; // failure exit
 }
 ADC1->ISR |= 0X800; // clearing EOCAL

Do not use read-modify-write on ISR register and be careful with CR as it also has "rs" bits like ISR. Probably the most important - you are not waiting for ADDIS command to complete. And ultimately I would want the watchdog to act if the code gets stuck in that loop...

adaniel
adanielAuthor
Associate III
December 24, 2020

Thanks Piranha for your attention, but it doesn't help:

1 - STM32L030F4P6 chip on my desk, and on my board!

2 - Read-modify-write instructions? there is no such a warning in the datasheet. I also have separated them in 2 parts with no avail.

3 - ADDIS: I added a waiting loop with no result

4 - You ignore the fact that Atollic 9.2.0 compiles successfully!

5 - The watchdog works and the loop exits FALSE.

Hard to admit that you have a problem? I don't, I completed my project without ADC calibration.

My question is definitely not answered.

TDK
Super User
December 24, 2020

> 1 - STM32L030F4P6 chip on my desk, and on my board!

Can you link the product page to prove that it does exist? Google shows no hits. Maybe you have a counterfeit part. Hard to prove a negative.

> 2 - Read-modify-write instructions? there is no such a warning in the datasheet. I also have separated them in 2 parts with no avail.

> ADC1->ISR |= 0X800; // clearing EOCAL

This clears ALL flags, not just EOCAL. This is covered in the reference manual (for STM32L0X0). To clear only EOCAL:

ADC1->ISR = ADC_ISR_EOCAL;

There are other requirements for starting calibration and you're not checking for them all. From the reference manual (for STM32L0X0):

The software is allowed to set ADCAL only when the ADC is disabled (ADCAL=0, ADSTART=0, ADSTP=0, ADDIS=0 and ADEN=0).

"If you feel a post has answered your question, please click ""Accept as Solution""."
adaniel
adanielAuthor
Associate III
December 25, 2020

> 1 - Sorry, my mistake, the chip is STM32L010F4P6

> 2 - Clearing all flags? good, this is what I want

> 3 - ADCAL=0, ADSTART=0, ADSTP=0, ADDIS=0 and ADEN=0.: this is the RESET state

> 4 - Please stop seeking what is wrong in the code: it works fine with ATOLLIC. STM32CUBE has a problem!

> 5 - In the past, you gave me an excellent advice: to look at the generated assembler code. I would like to do that. I cannot find any assembler window.

TDK
Super User
December 25, 2020

> 4 - Please stop seeking what is wrong in the code: it works fine with ATOLLIC. STM32CUBE has a problem!

Okay, must be an STM32CubeIDE issue then if you say the code is right. Use ATOLLIC instead.

Good luck.

"If you feel a post has answered your question, please click ""Accept as Solution""."
adaniel
adanielAuthor
Associate III
December 25, 2020

Thanks for the advice! Since Atollic is dead and only STM32 is being updated, I wish to use STM32.The only problem, for the time being , is with the ADC calibration which I don't need. In my project the ADC is used to monitor a PIR device for motion detection. The exact value of the A/D is unimportant; the only relevant data is its rate of change.

Anyway, thanks for your attention. I see the case closed, but no solved, until some update in the future?

Piranha
Principal III
January 3, 2021

The calibration complete waiting has one more requirement. RM0451 section 13.3.3:

The ADCAL bit can remain set for some time even after EOCAL has been set. As a result, the software must wait for ADCAL=0 after EOCAL=1 to be able to set ADEN=1 for next ADC conversions.

After calibration ADC enable and conversion start cannot be done in a single operation. One must enable ADEN, wait for ADRDY and only then ADSTART can be set.

ADC1->CR |= 5; // ADC started

ADRDY: ADC ready

This bit is set by hardware after the ADC has been enabled (bit ADEN=1) and when the ADC reaches a state where it is ready to accept conversion requests.

There is nothing technically wrong with read-modify-write operations, just some of them are unnecessary and can be replaced with simple writes. Also the fact that code compiles successfully or even works with some compiler version with some settings, doesn't prove it's correct. The code ir correct only when it formally guarantees the required sequence of actions.