Skip to main content
Diltech
Associate
March 25, 2026
Question

BlueNRG-1 and delay_ms() for OneWire read

  • March 25, 2026
  • 3 replies
  • 123 views

Hi all,

I'm trying to create a project to read a temperature sound like a DS18B20. The problem is that I need a precise and stable delay time. Using Systick isn't possible because there's a conflict when using BLE. I tried using an MFT, but I can't create a function to vary the delay. I based my approach on a timer in MFT_Mode1 and a prescaler 80-1 on the 16MHz oscillator.

static inline void delay_us(uint32_t us) {
uint32_t ticks = us / 10; // 1 tick ≈ 10 µs
if (ticks == 0) ticks = 1;

uint16_t start = MFT_GetCounter2(MFT1);

while ((uint16_t)(MFT_GetCounter2(MFT1) - start) < ticks) {

}
}


static void MFT1_Reset(void) {
MFT_SetCounter2(MFT1,0);
}

static uint16_t MFT1_Get(void) {
return MFT_GetCounter2(MFT1);




Even if I vary my e.g. delay_us(2500) , I still get pulses at 10µs.

 

For test in loop

/* Start MFT timers */
MFT_Cmd(MFT1, ENABLE);

while (1) {

GPIO_SetBits(GPIO_Pin_6);
 delay_us(250000); // 250 ms
 GPIO_ResetBits(GPIO_Pin_6);
 delay_us(250000);


}

 Thank for help

3 replies

Peter BENSCH
Technical Moderator
March 25, 2026

Main issues:

  1. Your busy‑wait code is fine if the MFT runs as a free‑running counter.
    If the MFT is configured for PWM/compare/toggle so that the counter is reset every 10µs, then:
    (uint16_t)(MFT_GetCounter2(MFT1) - start)​
    can never grow beyond that period, so the delay function will always return after ~10 µs, no matter what us you pass.
  2. With 16MHz and prescaler 80-1: ftimer = 16MHz/80 = 200kHz -> 5µs/tick but you assume 1 tick ~10µs. That gives you a ×2 timing error.

What to do:

  1. Make MFT a pure time base
    • Mode: free‑running, no auto‑reload that resets at a compare value
    • Disable any output‑compare / toggle mode that restarts the counter
    • Do not touch the counter in any ISR.
      Prefer 1 µs ticks (pseudo code):
      mftInit.MFT_Prescaler = 16-1 ; // 16MHz/16 = 1MHz -> 1 µs per tick
      mftInit.MFT_Period = 0xFFFF; // free-running​
  2. Correct delay_us

    Since the counter is 16-bit, you can measure directly up to a maximum of about 65ms at a time. For longer delays (e.g. 250ms), you do:

    static inline void delay_us(uint32_t us)
    {
     if (us == 0) return;
     uint16_t start = MFT_GetCounter2(MFT1);
     while ((uint16_t)(MFT_GetCounter2(MFT1) - start) < (uint16_t)us) { }
    }
    
    void delay_us_blocking(uint32_t us)
    {
     while (us > 60000)
     {
     delay_us(60000);
     us -= 60000;
     }
     if (us) delay_us(us);
    }

    Test (different calls at lines 6 and 8):

    MFT_Cmd(MFT1, ENABLE);
    
    while (1)
    {
     GPIO_SetBits(GPIO_Pin_6);
     delay_us_blocking(250000); // ~250ms
     GPIO_ResetBits(GPIO_Pin_6);
     delay_us_blocking(250000); // ~250ms
    }
  3. Ensure GPIO_Pin_6 is configured as GPIO output, not as an MFT alternate function. Otherwise you’re seeing the timer PWM (10µs period) on the scope, not your software delay.

Hope that helps?

Regards
/Peter

Peter BENSCH
Technical Moderator
March 25, 2026

...or have a look at this solution that nimaltd published on Github, which was discussed, among other places, here.

Andrew Neil
Super User
April 2, 2026

You might also look at synthesising the timing using UART or SPI - Analog Devices have an App Note on that...

 

eg, see: Dallas (sic) iButton and UART

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.