Skip to main content
MasterPhi
Associate II
June 16, 2026
Solved

STM32C071: ADC overrun when erasing flash

  • June 16, 2026
  • 2 replies
  • 65 views

Hi,

 

I met a strange issue of ADC overrun during flash erase.

The ADC is configured with circular DMA+TIM3 triggered at 1khz:

static void ADC_Config(void) {
/* Enable clock */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
RCC->APBENR2 |= RCC_APBENR2_ADCEN;
RCC->APBENR1 |= RCC_APBENR1_TIM3EN;
/* ADC Init */
ADC1->CR |= ADC_CR_ADVREGEN;
uint32_t tick = SysTick->VAL;
/* Startup delay */
while ((tick - SysTick->VAL) < 960);
/* Calibration */
ADC1->CR |= ADC_CR_ADCAL;
while (ADC1->CR & ADC_CR_ADCAL);
/* TIM3 trigger, DMA enable */
ADC1->CFGR1 = ADC_CFGR1_EXTEN_0 | 3 << ADC_CFGR1_EXTSEL_Pos | ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN;
/* Use 14MHz ADC clock */
ADC1->CFGR2 = ADC_CFGR2_CKMODE_0;
/* Enable overrun interrupt */
ADC1->IER = ADC_IER_OVRIE;
/* Long sampling time */
ADC1->SMPR = ADC_SMPR_SMP1_0 | ADC_SMPR_SMP1_1 | ADC_SMPR_SMP1_2;
/* Vref and Tint enable */
ADC1->CHSELR = ADC_CHSELR_CHSEL9 | ADC_CHSELR_CHSEL10;
ADC->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN;
/* Enable ADC */
ADC1->ISR |= ADC_ISR_ADRDY;
ADC1->CR |= ADC_CR_ADEN;
while (!(ADC1->ISR & ADC_ISR_ADRDY));
/* DMA Init */
/* ADC1 request */
DMAMUX1_Channel0->CCR = 5;
DMA1_Channel1->CPAR = (uint32_t) &ADC1->DR;
DMA1_Channel1->CMAR = (uint32_t) AnBuf;
DMA1_Channel1->CNDTR = 2;
/* Size 16bits, memory increment, circular mode */
DMA1_Channel1->CCR = DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_MINC | DMA_CCR_CIRC;
DMA1_Channel1->CCR |= DMA_CCR_EN;
/* TIM Init */
/* UEV as TRGO */
TIM3->CR2 = 2 << TIM_CR2_MMS_Pos;
TIM3->PSC = 12 - 1;
TIM3->ARR = 1000 - 1;
TIM3->CR1 |= TIM_CR1_CEN;
/* Enable ADC */
NVIC_SetPriority(ADC1_IRQn, 0);
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
NVIC_EnableIRQ(ADC1_IRQn);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
/* Start ADC conversion */
ADC1->CR |= ADC_CR_ADSTART;
}

I’m aware that accessing flash during operation will block the CPU in a waiting state, so the flash erasing function is executed in RAM (even if it’t the case DMA should be unaffected as it’s a difference bus master ?):

__ramfunc int NVM_fErase(uint_fast8_t Page) {
if (Page >= NVM_PAGE_CNT) {
return -1;
}
__disable_irq();
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
__enable_irq();
while (FLASH->CR & FLASH_CR_LOCK);
/* Clear all error flags */
FLASH->SR = 0x0000FFFF;
while (FLASH->SR & FLASH_SR_BSY1) {
if (FLASH->SR & (FLASH_SR_PGSERR | FLASH_SR_SIZERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_PROGERR)) {
FLASH->CR |= FLASH_CR_LOCK;
return -1;
}
}
FLASH->CR |= FLASH_CR_PER;
MODIFY_REG(FLASH->CR, FLASH_CR_PNB, ((NVM_BASE_ADDR - 0x08000000) / NVM_PAGE_SIZE + Page) << FLASH_CR_PNB_Pos);
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY1) {
if (FLASH->SR & (FLASH_SR_PGSERR | FLASH_SR_SIZERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_PROGERR)) {
FLASH->CR |= FLASH_CR_LOCK;
return -1;
}
}
FLASH->SR = FLASH_SR_EOP;
FLASH->CR &= ~FLASH_CR_PER;
FLASH->CR |= FLASH_CR_LOCK;
return 0;
}

Also to prevent instruction fetching of other interrupts:

  • Vector table is copied to RAM
  • IRQ handlers are in RAM

I also tried to catch unexpected flash access with MPU by disabling flash and ROM region access:

{ARM_MPU_RBAR(0, 0x08000000),
ARM_MPU_RASR(1UL, ARM_MPU_AP_NONE, 0UL, 1UL, 0UL, 0UL, 0x00UL, ARM_MPU_REGION_SIZE_128KB)},
{ARM_MPU_RBAR(1, 0x1FFF0000),
ARM_MPU_RASR(1UL, ARM_MPU_AP_NONE, 0UL, 1UL, 0UL, 1UL, 0x00UL, ARM_MPU_REGION_SIZE_32KB)},

 

I stripped down a minimal demo running on Nucleo-C071RB build with IAR 9.70.4, once you press the button you should enter ADC1_IRQHandler with OVR flag set.

 

Best answer by MasterPhi

Issue is resolved by wait on SR_CFGBSY.

With a more detailed tracing it revealed that the SR_BSY1 wait after CR_STRT didn’t hit, the code actually halted on FLASH->CR &= ~FLASH_CR_PG. 

The code was based on a older reference manual where BSY1 flag is used for waiting, while it changed to CFGBSY now:

To erase a page (2 Kbytes), proceed as follows:
1. Check that no flash memory operation is ongoing on the targeted bank, by checking the 
BSY1 or BSY2 bit of the FLASH status register (FLASH_SR).
2.  Check and clear all error programming flags due to a previous programming. If not, 
PGSERR is set.
3.  Check that CFGBSY is cleared.
4.  Set the PER bit and select the page to erase (BKER, PNB) in the FLASH control 
register (FLASH_CR).
5.  Set the STRT bit of the FLASH control register (FLASH_CR).
6.  Wait until the CFGBSY bit of the FLASH status register (FLASH_SR) is cleared.

 

Also it is noted that:

The FLASH_CR register cannot be written when the BSY1 bit of the FLASH status register 
(FLASH_SR) is set. Any attempt to write to this register with the BSY1 bit set causes the 
AHB bus to stall until the BSY1 bit is cleared.

 

So what’s the issue waiting on BSY1 ?

2 replies

MasterPhi
MasterPhiAuthorBest answer
Associate II
June 17, 2026

Issue is resolved by wait on SR_CFGBSY.

With a more detailed tracing it revealed that the SR_BSY1 wait after CR_STRT didn’t hit, the code actually halted on FLASH->CR &= ~FLASH_CR_PG. 

The code was based on a older reference manual where BSY1 flag is used for waiting, while it changed to CFGBSY now:

To erase a page (2 Kbytes), proceed as follows:
1. Check that no flash memory operation is ongoing on the targeted bank, by checking the 
BSY1 or BSY2 bit of the FLASH status register (FLASH_SR).
2.  Check and clear all error programming flags due to a previous programming. If not, 
PGSERR is set.
3.  Check that CFGBSY is cleared.
4.  Set the PER bit and select the page to erase (BKER, PNB) in the FLASH control 
register (FLASH_CR).
5.  Set the STRT bit of the FLASH control register (FLASH_CR).
6.  Wait until the CFGBSY bit of the FLASH status register (FLASH_SR) is cleared.

 

Also it is noted that:

The FLASH_CR register cannot be written when the BSY1 bit of the FLASH status register 
(FLASH_SR) is set. Any attempt to write to this register with the BSY1 bit set causes the 
AHB bus to stall until the BSY1 bit is cleared.

 

So what’s the issue waiting on BSY1 ?

ST Technical Moderator
June 23, 2026

Hello ​@MasterPhi 

Yes. To ensure a safe write operation on flash memory, check both the BSY1 bit and the CFGBSY bit.

Mentioning only the BSY1 bit in RM0490 Rev 5 was incorrect information. The new version, RM0490 Rev 6, corrects this point and clearly states that both bits must be checked in the Embedded flash memory (FLASH) section.
BR
Gyessine

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question.