cancel
Showing results for 
Search instead for 
Did you mean: 

BlueNRG-1 and delay_ms() for OneWire read

Diltech
Associate II

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 3
Peter BENSCH
ST Employee

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

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Peter BENSCH
ST Employee

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

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Andrew Neil
Super User

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.