how to PWM Frequency stm32duino and resolution

Post here first, or if you can't find a relevant section!
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: how to PWM Frequency stm32duino and resolution

Post by dannyf »

I know all the registers to use, I get bit arithmetics, but what is the syntax?
it might be simpler to just check the 1k-page reference manual. most of those bits are in CCER but there should be a section on the right bits for all of that.

beats out going through the HAL functions.
geekfun
Posts: 5
Joined: Wed Jul 28, 2021 10:34 pm

Re: how to PWM Frequency stm32duino and resolution

Post by geekfun »

fpiSTM wrote: Thu Jun 11, 2020 4:30 pm You can try this instead of analog API:

HardwareTimer examples for PWM:
https://github.com/stm32duino/STM32Exam ... setPWM.ino
https://github.com/stm32duino/STM32Exam ... ration.ino


Wiki:
https://github.com/stm32duino/wiki/wiki ... er-library
I know I am replying to a pretty old post but I'm not sure where else to post. I followed the examples and get a working PWM, sort of. My application, which is a motor controller relies on being able to reset the PWM to change motor speed. I am using a STM32F103C8 bluepill and the following code to get the PWM running which I put into a function called when the user of the machine calls for a speed change. I can only execute this function 100 times until the processor stops (timer keeps running with the last PWM setting though, so the STM32 is not dead). When executing this test program main loop stops after the 50th iteration. Can you offer any insight into what I did wrong?

Thanks in advance for any help,
Steve

Code: Select all

#include<Wire.h>
#include <LiquidCrystal_I2C.h>
#define pwm_pin  PB9
long int loop_cntr;
LiquidCrystal_I2C lcd(0x27, 20, 4);

void pwm_set(int freq, int duty)
{
  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_pin), PinMap_PWM);
  uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_pin), PinMap_PWM));
  HardwareTimer *MyTim = new HardwareTimer(Instance);
  MyTim->setPWM(channel, pwm_pin, freq, duty); // 5 Hertz, 10% dutycycle
}

void setup(void) {
  pinMode(pwm_pin, OUTPUT);  
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.

  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("LCD OK");
  lcd.setCursor(8,0);
  loop_cntr=0;
}

void loop() {

  ++ loop_cntr;
      lcd.print("     ");
        lcd.setCursor(8,0);
      lcd.print(loop_cntr);
        lcd.setCursor(8,0);  
  pwm_set(20,10);
   delay(100);
  pwm_set(5,10);
   delay(100);
}
Last edited by geekfun on Thu Jul 29, 2021 10:53 pm, edited 1 time in total.
geekfun
Posts: 5
Joined: Wed Jul 28, 2021 10:34 pm

Re: how to PWM Frequency stm32duino and resolution

Post by geekfun »

I found my answer in a post made by fredbox (Thanks!) and here is the working test program with the new stuff for the next person who has this trouble:

Code: Select all

#include<Wire.h>
#include <LiquidCrystal_I2C.h>
#define pwm_pin  PB9
long int loop_cntr;
LiquidCrystal_I2C lcd(0x27, 20, 4);

  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_pin), PinMap_PWM);
  uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_pin), PinMap_PWM));
  HardwareTimer *MyTim = new HardwareTimer(Instance);

void pwm_set(int duty)
{
MyTim->setCaptureCompare(channel, duty, PERCENT_COMPARE_FORMAT);
  delay(50);
}

void setup(void) {
  pinMode(pwm_pin, OUTPUT);  
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  MyTim->setPWM(channel, pwm_pin, 1, 1); 
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("LCD OK");
  lcd.setCursor(8,0);
  loop_cntr=0;
}

void loop() {
  ++ loop_cntr;
      lcd.print("     ");
        lcd.setCursor(8,0);
      lcd.print(loop_cntr);
        lcd.setCursor(8,0);  
  pwm_set(30);
   delay(1000);
  pwm_set(1);
   delay(1000);
}
geekfun
Posts: 5
Joined: Wed Jul 28, 2021 10:34 pm

Re: how to PWM Frequency stm32duino and resolution

Post by geekfun »

fpiSTM wrote: Thu Jun 11, 2020 4:30 pm You can try this instead of analog API:

HardwareTimer examples for PWM:
https://github.com/stm32duino/STM32Exam ... setPWM.ino
https://github.com/stm32duino/STM32Exam ... ration.ino


Wiki:
https://github.com/stm32duino/wiki/wiki ... er-library
I am coming back once again to what may be a dry well, as this thread on PWM seems dead, but here goes anyway.
I have got PWM working using the timer syntax as I understand it but what I really need is two PWM pins, both running at 20 Hertz, and I need to be able to vary the duty cycle. I modified my test program as best I could (I have not found the documentation yet that explains this easily for me) and it will compile but does not function correctly. See the line in the code that says this kills ability to change the duty cycle.

Anyone willing to take a look and help me to get on the right track?

Code: Select all

#include<Wire.h>
#include <LiquidCrystal_I2C.h>
#define pwm_lathe  PA9
#define pwm_mill PA8
long int loop_cntr;
LiquidCrystal_I2C lcd(0x27, 20, 4);

  TIM_TypeDef *InstanceMill = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_mill), PinMap_PWM);
  uint32_t channelMill = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_mill), PinMap_PWM));
  HardwareTimer *MyTimMill = new HardwareTimer(InstanceMill);
  
  TIM_TypeDef *InstanceLathe = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_lathe), PinMap_PWM);
  uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_lathe), PinMap_PWM));
  HardwareTimer *MyTimLathe = new HardwareTimer(InstanceLathe);

void pwm_Mill(int duty)
{
  MyTimMill->setCaptureCompare(channel, duty, PERCENT_COMPARE_FORMAT);
  delay(50);
}

void pwm_Lathe(int duty)
{
  MyTimLathe->setCaptureCompare(channel, duty, PERCENT_COMPARE_FORMAT);
  delay(50);
}

void setup(void) {
//  pinMode(pwm_pin, OUTPUT);  
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  MyTimLathe->setPWM(channel, pwm_lathe, 20, 1);   
//  MyTimMill->setPWM(channel, pwm_mill, 20, 1); // uncommmenting this kills abililty to change duty cycle also kills LCD
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("LCD OK");
  lcd.setCursor(8,0);
  loop_cntr=0;
}

void loop() {
  ++ loop_cntr;
      lcd.print("     ");
        lcd.setCursor(8,0);
      lcd.print(loop_cntr);
        lcd.setCursor(8,0);  
  delay(2000);
  pwm_Lathe(1);
  pwm_Mill(30);
   delay(2000);
  pwm_Lathe(30);
  pwm_Mill(1);
   delay(1000);
}
ABOSTM
Posts: 60
Joined: Wed Jan 08, 2020 8:40 am
Answers: 7

Re: how to PWM Frequency stm32duino and resolution

Post by ABOSTM »

Hi @geekfun,

There are few mistakes in your sketch:
1) in the killing line, channel should be channelMill :
// MyTimMill->setPWM(channelMill, pwm_mill, 20, 1); // uncommmenting this kills abililty to change duty cycle also kills LCD

2) Because you choose 2 channels from the same timer TIM1, you should create new HardwareTimer instance only once.
for example:

Code: Select all

HardwareTimer *[b]MyTim [/b]= new HardwareTimer(InstanceLathe);
and then use MyTim instead of MyTimLathe and MyTimMill

3) you use PA9 for pwm_lathe pin, but on bluepill F103C8, this pin is already used for serial:
https://github.com/stm32duino/Arduino_C ... 3Cx.h#L144
ABOSTM
Posts: 60
Joined: Wed Jan 08, 2020 8:40 am
Answers: 7

Re: how to PWM Frequency stm32duino and resolution

Post by ABOSTM »

4) also in pwm_Lathe()
pwm_Mill->setCaptureCompare(channelMill, duty, PERCENT_COMPARE_FORMAT);
geekfun
Posts: 5
Joined: Wed Jul 28, 2021 10:34 pm

Re: how to PWM Frequency stm32duino and resolution

Post by geekfun »

Greetings, ABOSTM, you are my hero today. I now have a working sketch which I will post here for any others who have an issue with getting more than one PWM going and need a known good example.

I've attached a screen shot from my scope showing the two PWM signals alternating from 10% duty to 90% duty.
DS1Z_QuickPrint1.png
DS1Z_QuickPrint1.png (37.47 KiB) Viewed 4031 times
Here's the code which produced this waveform, which was facilitated by the input from ABOSTM:

Code: Select all

#define pwm_lathe  PB0
#define pwm_mill PB1

  TIM_TypeDef *InstanceMill = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_mill), PinMap_PWM);
  uint32_t channelMill = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_mill), PinMap_PWM));
  HardwareTimer *MyTim = new HardwareTimer(InstanceMill);
  
  TIM_TypeDef *InstanceLathe = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_lathe), PinMap_PWM);
  uint32_t channelLathe = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_lathe), PinMap_PWM));

void pwm_Mill(int duty)
{
  MyTim->setCaptureCompare(channelLathe, duty, PERCENT_COMPARE_FORMAT);
  delay(50);
}
void pwm_Lathe(int duty)
{
  MyTim->setCaptureCompare(channelMill, duty, PERCENT_COMPARE_FORMAT);
  delay(50);
}

void setup(void) {
  MyTim->setPWM(channelLathe, pwm_lathe, 20, 1);   
  MyTim->setPWM(channelMill, pwm_mill, 20, 1); 
}

void loop() {
  pwm_Lathe(10);
  pwm_Mill(90);
   delay(100);
  pwm_Lathe(90);
  pwm_Mill(10);
   delay(100);
}
geekfun
Posts: 5
Joined: Wed Jul 28, 2021 10:34 pm

Re: how to PWM Frequency stm32duino and resolution

Post by geekfun »

I have attached the schematic and the full code for the PWM motor control. Both are available under GPL V3.

The schematic was developed using KiCAD.

Best regards,
Steve

Code: Select all

/*  Written by Steven E. Stock who retains all Copyrights, released 8-1-2021. 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You may have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_I2C_ADDR 0x3C
#define OLED_WIDTH 128
#define OLED_HEIGHT 32
#define pwm_lathe  PB0
#define pwm_mill PB1

  TIM_TypeDef *InstanceMill = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_mill), PinMap_PWM);
  uint32_t channelMill = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_mill), PinMap_PWM));
  HardwareTimer *MyTim = new HardwareTimer(InstanceMill);
  
  TIM_TypeDef *InstanceLathe = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pwm_lathe), PinMap_PWM);
  uint32_t channelLathe = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pwm_lathe), PinMap_PWM));

Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire);

int pwm = 0;
int pwm_set_Lathe = 0;
int pwm_set_Mill = 0;

int loop1 = 1;
int LatheActive = 1;
int MillActive = 0;

char person_pwm[3]; 
char percnt[1] = {'%'};
char pending[1] = {'P'};
  
int ButtonUp   = 0;
int ButtonDown = 0;
int ButtonSwitch  = 0;
int ButtonCommit = 0;

void pwm_Mill(int duty)
{
  MyTim->setCaptureCompare(channelLathe, duty, PERCENT_COMPARE_FORMAT);
  delay(50);
}
void pwm_Lathe(int duty)
{
  MyTim->setCaptureCompare(channelMill, duty, PERCENT_COMPARE_FORMAT);
  delay(50);
}

void setup() 
{
  pinMode(PC13, OUTPUT);  
  pinMode(PA10, OUTPUT); //pwm pin
  pinMode(PB5, INPUT);
  pinMode(PB4, INPUT);
  pinMode(PB3, INPUT);
  pinMode(PA15, INPUT);
  
  MyTim->setPWM(channelLathe, pwm_lathe, 20, 1);   
  MyTim->setPWM(channelMill, pwm_mill, 20, 1); 
  
  ButtonCommit = digitalRead(PA15);
  ButtonDown = digitalRead(PB4);
  ButtonUp = digitalRead(PB5);
  ButtonSwitch = digitalRead(PB3);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) 
  { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.setRotation(2);
  pwm_Mill(pwm);
}

void oled_write() {
  display.clearDisplay();
  display.display();
  display.setTextSize(3);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(45,5);
  display.print(person_pwm);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10,25);
  if (LatheActive) {display.print("Lathe");} else {display.print("Mill");}
  
  display.display(); // actually display all of the above
}

void loop() {

  if ((!ButtonUp) && (pwm<94)) {
    pwm++;
    sprintf(person_pwm, "%02d", pwm);
    person_pwm[2]= *pending;
    oled_write();
  }
  
  if ((!ButtonDown) && (pwm>0)) {
    pwm--;
    sprintf(person_pwm, "%02d", pwm);
    person_pwm[2]= *pending;
    oled_write();
  }
  
  if (!ButtonSwitch) {
    if (LatheActive) {LatheActive = 0; MillActive=1;pwm = pwm_set_Mill;} else {LatheActive = 1; MillActive=0;pwm = pwm_set_Lathe;}
    sprintf(person_pwm, "%02d", pwm);
    person_pwm[2]= *percnt;
    oled_write();
    pwm_Mill(pwm);
  }

  if (!ButtonCommit) {
    if (LatheActive) {pwm_set_Lathe = pwm; pwm_Lathe(pwm);} else {pwm_set_Mill = pwm; pwm_Mill(pwm);}
    person_pwm[2]= *percnt;
    oled_write();
   }

//  sprintf(person_pwm, "%02d", pwm);
  delay(200); // Pause for however long feels right

  ButtonCommit = digitalRead(PA15);
  ButtonDown = digitalRead(PB4);
  ButtonUp = digitalRead(PB5);
  ButtonSwitch = digitalRead(PB3);
  
  if (loop1 == 1) {sprintf(person_pwm, "%02d", pwm);person_pwm[2]= *percnt;oled_write();loop1 = 0;}
}
Attachments
Screenshot from 2021-08-01 19-12-04.png
Screenshot from 2021-08-01 19-12-04.png (27.36 KiB) Viewed 4010 times
ABOSTM
Posts: 60
Joined: Wed Jan 08, 2020 8:40 am
Answers: 7

Re: how to PWM Frequency stm32duino and resolution

Post by ABOSTM »

@geekfun ,
thanks for your feedback, and for sharing your code/schematics.
For information there is a dedicated section to share code: Code snippets
viewforum.php?f=41
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: how to PWM Frequency stm32duino and resolution

Post by mrburnette »

alfrond wrote: Thu Nov 26, 2020 6:16 pm ...
I am too trying to get pwm/compl outuputs/dead time to run on the STM32.
...
Anyone who can help out? I know all the registers to use, I get bit arithmetics, but what is the syntax?
...
Hijacking a thread will often leave you dangling on a closed thread. Best to ask your own question in a separate post.
But, you did not give us any info... what chip+board and what core?

If you are just looking for general examples, google searches turn up a fair number.

https://www.digikey.com/en/maker/projec ... 43c0b08cc6

https://github.com/stm32duino/STM32Exam ... eripherals

https://dannyelectronics.wordpress.com/ ... it-timers/

https://www.st.com/resource/en/applicat ... ronics.pdf

And numerous YouTube and vendor videos.
Post Reply

Return to “General discussion”