Question about Bluepill arduino using OnePulse mode

Post here first, or if you can't find a relevant section!
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Question about Bluepill arduino using OnePulse mode

Post by xlwww »

I use BluePill and I'm trying to put Timer2 channel1 in OnePulse mode, how can I make an interrupt at the end of the pulse to handle the task, the code I found can't run well, please help me, thank you!
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

Show us what you tried, and in what way did it not work?
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

ozcar wrote: Tue Dec 27, 2022 11:31 am Show us what you tried, and in what way did it not work?
I am using Timer2 channel1 (PA0) to drive the DHT11 sensor, saving CPU resources for computationally intensive work. DHT11 needs 18ms low-level trigger, I need to use the OnePulse mode of the timer to generate a pulse first, and then quickly turn the timer into capture mode to capture the return pulse of DHT. I have completed the second half of the work of capturing DHT11 signals, but the previous OnePulse is not working properly. Below is my activation code

```
void Request() /* Microcontroller send request */
{
pinMode(DHT11, PWM);
// digitalWrite(DHT11, LOW);
// delay(18); /* wait for 18ms */

uint16_t pulseDelay = 20000;
uint16_t pulseWidth = 19000;
Timer2.pause(); // stop the timers before configuring them

timer_oc_set_mode(TIMER2, 1, TIMER_OC_MODE_PWM_1, TIMER_OC_PE);

Timer2.setPrescaleFactor(72); // 1 microsecond resolution
Timer2.setOverflow(pulseWidth + pulseDelay-1);
Timer2.setCompare(TIMER_CH1, pulseDelay);

// counter setup in one pulse mode, as slave triggered by External input for Timer 2
TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode
TIMER2_BASE->SMCR = ( TIMER_SMCR_TS_ETRF | TIMER_SMCR_SMS_TRIGGER );

TIMER2_BASE->CCER = TIMER_CCER_CC1E ; // enable channels 1 and 2
Timer2.attachInterrupt(TIMER_CH1,handler_channel_1);
Timer2.refresh(); // start timer 2
Timer2.resume(); // let timer 2 run
// digitalWrite(DHT11,HIGH); /* set to high pin */
}

void handler_channel_1(void)
{
// turn the timer into capture mode
}
```
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

I'm not familiar with DHT11 at all, but two things come to mind:

Firstly, maybe you have run into a problem like here - viewtopic.php?f=7&t=1563 . That did result in a change to the hardwaretimer code, but it still may be necessary to move the Timer2.refresh() to after the Timer2.attachInterrupt() to avoid the interrupt routine being triggered by the refresh() call.

Secondly, the ISR will be called at the end of the "CCR time", when maybe you want it to be at the end of the "ARR time". Have you changed or checked TIMER_CCER_CC1P ?

I suppose the third possibility is both of the above, and the fourth, neither of them...
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

It's still not working, can someone help me? I have written my understanding below, thank you.

Code: Select all


void Request()      /* Microcontroller send request */
{

  uint16_t PulseLOW = 20000; // should > 18ms
  uint16_t PulseHIGH = 18000; // not important
  
  pinMode(DHT11, PWM);

  Timer2.pause(); // stop the timers before configuring them
  timer_oc_set_mode(TIMER2, 1, TIMER_OC_MODE_PWM_2, TIMER_OC_PE);//set PWM Mode2,and enable
  Timer2.setPrescaleFactor(72); // 1 microsecond resolution
  Timer2.setOverflow(PulseLOW + PulseHIGH-1);
  Timer2.setCompare(TIMER_CH1, PulseLOW);
 // Triggered after PulseLOW
  Timer2.attachInterrupt(TIMER_CH1,Response);
  
  // counter setup in one pulse mode
  TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode
  
  // as slave triggered by External input for Timer 2,
  //I don't quite understand this sentence and commented it
  //TIMER2_BASE->SMCR = ( TIMER_SMCR_TS_ETRF | TIMER_SMCR_SMS_TRIGGER );
  
  TIMER2_BASE->CCER =  TIMER_CCER_CC1E ; // enable channels 1 
  
  Timer2.refresh(); // start timer 2
  Timer2.resume(); // let timer 2 run

/*
                    Using PWM Mode 2,but not work

  _______20MS__________-------------------18MS-------------------___________
  ^                    ^                                         ^
  |<----PulseLOW------>|<-- PulseHIGH, but don't need attention->|      
                       ^
                       |
                       
              Compare1Interrupt
              execution Response(),
           Change the mode of the Timer2

 */

}
 

void Response()
{
/*Change the mode of the Timer2*/
}


ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

I should have realised that you are using a Leaflabs/Libmaple based core, not the "official" STM one. For a long time now I have only used the STM core, so what I said before may not apply, but then the underlying hardware is the same so it is possible that you could run into similar problems.

The symptoms of the two (potential) problems that I mentioned would be the pulse duration being incorrect and/or the signal might be inverted (high first, then low).

"Does not work" is a bit vague. Do you have any way to check what is happening? Even with no additional equipment, there would be ways to figure things out, but could take some effort on your part.

Does the ISR ever get control? If so, how much later is that from the time you did the Timer2.resume() ? Hint- micros() is your friend.

Is the (pulled-up) output line high or low say 1ms after the Timer2.resume() ? What about when the ISR gets control, high or low? Hint - if you tie the output line to a spare pin configured for input, then you can tell at any point in your code whether the timer is driving the line low or not. While you are about it, check for high or low before you enable the time channel too.
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

ozcar wrote: Wed Dec 28, 2022 11:51 am ... if you tie the output line to a spare pin configured for input, then you can tell at any point in your code whether the timer is driving the line low or not.
I was thinking about this later, and maybe you don't even need a "spare" pin to do that. In viewtopic.php?t=1452 reading from an output pin gets mentioned (although the thread title is the opposite of that).

I also thought of a couple of other things that might be worth checking.

When you turn on timer register flags like TIMER_CR1_OPM and TIMER_CCER_CC1E, is it really your intention to turn off all the other bits in the same register?

In one pulse mode, TIMER_CR1_CEN will be automatically cleared disabling the counter. However, when your Response() routine is entered, that will not have happened yet. You did not show what you do in Response(), so hard to say if that could cause you some trouble.
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

I don't have a DHT11 to test with, but this seems to work for me. However it is written for the official STM core as that is all I use now, and I tried it on a F401 board. As far as I know it does not do anything that could not work on F103 Bluepill. It works the same regardless of whether one pulse mode is used or not.

To use it you'd either have to adapt it for the core you are using, or else change the rest of your code to work with the official STM core. It does at least show an easy way to see what the pulse looks like (as it stands, the crude 1ms sampling might not be fast enough to check the DHT11 response).

Code: Select all

/*
  The code for getting the timer and channel number for a pin is from the All-in-one setPWM example
  https://github.com/stm32duino/STM32Examples/blob/main/examples/Peripherals/HardwareTimer/All-in-one_setPWM/All-in-one_setPWM.ino .
*/

/*
  pwmpin must have HardwareTimer capability
*/

#define pwmpin  D3    // aka DHT11  external pullup on this pin


HardwareTimer *MyTim;
uint32_t channel;

void Response()
{
  MyTim->pauseChannel(channel);
 /* ... */
}

void setup()
{
  Serial.begin(115200);
  Serial.println("setup()");
  
  pinMode(pwmpin,INPUT);        // without this, pwmpin was observed to be low before timer was resumed.
 
  // Automatically retrieve TIM instance and channel associated to pwmpin
  // This is used to be compatible with all STM32 series automatically.
  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwmpin), PinMap_PWM);
  channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwmpin), PinMap_PWM));
 
  // Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished.
  MyTim = new HardwareTimer(Instance);

  Serial.print(digitalRead(pwmpin));   // check that pwmpin is high or pulled up before timer enabled
  
  MyTim->setMode(channel, TIMER_OUTPUT_COMPARE_PWM2, pwmpin);
  MyTim->setOverflow(40*1000, MICROSEC_FORMAT);
  MyTim->setCaptureCompare(channel, 20*1000, MICROSEC_COMPARE_FORMAT);
  MyTim->refresh();
  MyTim->attachInterrupt(channel, Response);
  MyTim->resume();
  //TIM_HandleTypeDef *MyTimHandle = MyTim->getHandle();
  //MyTimHandle->Instance->CR1 |= TIM_CR1_OPM;   // not actually necessary to use one pulse mode 
  
  for ( int i=0; i<90; i++) { delay(1); Serial.print(digitalRead(pwmpin));}
  Serial.println(" "); 

  // Produces output like this. Trigger or starting point is just before the timer is started.
  // PWM2 mode without setting OPM, and without Response() routine attached:
  // 1000000000000000000001111111111111111111100000000000000000000111111111111111111110000...
  // PWM2 mode, setting OPM, but still without Response() routine attached:
  // 1000000000000000000001111111111111111111100000000000000000000000000000000000000000000...
  // PWM2 mode, with or without setting OPM, but with channel callback Response() routine doing MyTim->pauseChannel(channel):
  // 1000000000000000000001111111111111111111111111111111111111111111111111111111111111111...
  // ( with no sensor attached, so of course, no response )
  
}


void loop()
{
  // nothing to see here folks
}
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

My goodness. Because of debugging, I added a completely unrelated variable, and the code can run completely normally, including DHT11, everything is as I expected.
But when I want to delete these extraneous variables it doesn't work! ! ! ! I think it must be a matter of metaphysics, and I want to know what's going on? It seems unbelievable, but it happens, I kid you not.

This works perfectly fine!

Code: Select all

int32_t channel_1_start, channel_1_stop, channel_1,a=0,b=0,c=0;
//This will also work
int32_t channel_1_start, channel_1_stop, channel_1;
int32_t  a=0,b=0,c=0;
//This will still work as well
int32_t channel_1_start, channel_1_stop, channel_1;
int32_t d=0,e=0,f=0;


void loop(){
};

//*********Even put it here,it still work as well
int32_t d=0,e=0,f=0;

void Request(){
};
void Response(){
};
void handler_channel_1(){
};

But the following code can't drive DHT11 unexpectedly. a, b, c are completely useless variables, I even renamed them to d, e, f and it worked. But I can't delete them because DHT11 will not work properly without them.

Code: Select all


//This will not work
int32_t channel_1_start, channel_1_stop, channel_1; //delete abc variable
//This will still not 
int32_t a=0,b=0,c=0;//delete channel variable
//It seems that it will only work if the number of variables is greater than a value

void loop(){
};
void Request(){
};

void Response(){
};
void handler_channel_1(){
};
Using the logic analyzer I bought yesterday, I found that it is possible to do PWM all the time to activate the DHT11 without deleting the variable. But once those "useless" variables are deleted, if DHT11 does not respond, it can still generate PWM to generate a low level of 18MS, but once DHT11 responds once, it will never generate PWM again Come to drive DHT11. This is a metaphysical question, very bad.
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: Question about Bluepill arduino using OnePulse mode

Post by dannyf »

wouldn't it be easier to do this via a state machine?
Post Reply

Return to “General discussion”