sinus emulation with pwm on stm43f4-discovery howto?

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
flagman
Posts: 4
Joined: Wed Mar 26, 2014 3:41 pm

sinus emulation with pwm on stm43f4-discovery howto?

Post by flagman »

Hello all!
I`m trying to make emulation of sinus signal with pwm on stm32f4-discovery board.
Here is my code:

Code: Select all

#include "ch.h"
#include "hal.h"
#include math.h

static PWMConfig pwmcfg = {
  10000000, /* 10Mhz PWM clock frequency */
  220, /* PWM period 220 duty cycles */
  NULL,
  {
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_ACTIVE_HIGH, NULL},
  },
  0
};

int main(void){
         float s = 0; // holds sin() value
         int c = 0; //angle for sin() cycle counter
         int cc = 0; //direction -> 1 increment/ 0 decrement
        halInit();
        chSysInit();
        palSetPadMode(GPIOD, GPIOD_LED6, PAL_MODE_ALTERNATE(2));
   pwmStart(&PWMD4, &pwmcfg);
        pwmEnableChannel(&PWMD4, 3, 0);
        while(1){
      if (c>=90){
         cc=0;
      }
      if (c <=0 ){
         cc=1;
      }
      if (cc==0) c-=1;
      if (cc==1) c+=1;
                s= sin(c)*220;
      pwmEnableChannel(&PWMD4, 3, s);       
                chThdSleepMilliseconds(100);
        }
}

Works fine, but there must be more intelligent ways to do the same outside the main() loop by putting this into separate thread or use timers or interrupts to increment/decrement duty cycles... this one sample will be sessitive to chip load by other tasks, and inaccurate signal can`t be used as source for power elements.
Pls post here more intelligent solutions for this purpose with guarateed accuracy of signal.
Thanks!
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: sinus emulation with pwm on stm43f4-discovery howto?

Post by Giovanni »

You may use the PWM period callback and change the duty cycle there for the next cycle.

Note that those 10000000 Hz cannot be obtained from the main clock using a divider, what you will get is an approximation, if you enable assertions this is something that is trapped at runtime.

Giovanni
pito
Posts: 199
Joined: Sun Nov 06, 2011 3:54 pm

Re: sinus emulation with pwm on stm43f4-discovery howto?

Post by pito »

You may generate the sinus directly via DAC.
flagman
Posts: 4
Joined: Wed Mar 26, 2014 3:41 pm

Re: sinus emulation with pwm on stm43f4-discovery howto?

Post by flagman »

pito wrote:You may generate the sinus directly via DAC.

This is good point. Can you provide some example code for this?

I have tried to use timers callback function to change pwm duty cycle. It works, generally, but some thing wrong with main loop.

Code: Select all

#include "ch.h"
#include "hal.h"
#include "math.h"

extern float angle;
extern float pwm_duty;
const int pwm_period = 100;

float angle = 0;
float pwm_duty = 0;

void PwmCB(PWMDriver *pwmdrv){
   pwm_duty = sin(angle) * pwm_period;
   pwmEnableChannel(&PWMD4, 3, pwm_duty);
   if (angle >=180) angle = 0;
   angle += 0.5;
}

static PWMConfig pwmcfg = {
  50000, /* 50Khz PWM clock frequency */
  pwm_period, /* PWM period */
  PwmCB,  /* callback function - changes pwm duty cycle*/
  /* Only channel 4 enabled */
  {
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_ACTIVE_HIGH, NULL},
  },
  0
};


   
int main(void){
        halInit();
        chSysInit();             
        // configure GPIOD pin 15 and 13 as output
   palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL); // for direct handling LED
        palSetPadMode(GPIOD, 15, PAL_MODE_ALTERNATE(2)); // for pwm handling LED
   pwmStart(&PWMD4, &pwmcfg);
        while(1){
                palSetPad(GPIOD, 13); // set GPIOD 13 high
                chThdSleepMilliseconds(500);
      palClearPad(GPIOD, 13); // set GPIOD 15 low
        }
}

pwm managed led works fine, but led on gpiod 13 turns on and never get off.
Probably main thread hangs... at compile time i`ve got warning:
..\main.c(17): warning: #1035-D: single-precision operand implicitly converted to double-precision
angle += 0.5;
may be this causes this behavior of the board.
flagman
Posts: 4
Joined: Wed Mar 26, 2014 3:41 pm

Re: sinus emulation with pwm on stm43f4-discovery howto?

Post by flagman »

flagman wrote:Probably main thread hangs... at compile time i`ve got warning:
..\main.c(17): warning: #1035-D: single-precision operand implicitly converted to double-precision
angle += 0.5;
may be this causes this behavior of the board.

I`ve changed increment to 1, warning disappears, but no changes on board behavior... main loop hangs at sleep...
whats i`m doing wrong?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: sinus emulation with pwm on stm43f4-discovery howto?

Post by Giovanni »

You are calling a pwmEnableChannel() from a callback, you cannot call normal APIs from ISR context, only I-Class functions.

If you enable the state checker in chconf.h you get an assertion in case of such errors.

For more info see "Kernel Concepts" in the documentation.

Giovanni
flagman
Posts: 4
Joined: Wed Mar 26, 2014 3:41 pm

Re: sinus emulation with pwm on stm43f4-discovery howto?

Post by flagman »

Giovanni wrote:You are calling a pwmEnableChannel() from a callback, you cannot call normal APIs from ISR context, only I-Class functions.
Giovanni


like this?

Code: Select all

#include "ch.h"
#include "hal.h"
#include "math.h"

static WORKING_AREA(pwm_ThreadWorkingArea, 128);

extern double angle;
extern double pwm_duty;
const int pwm_period = 100;
double angle = 0.1;
double pwm_duty = 0;

void PwmCB(PWMDriver *pwmdrv){
   pwm_duty = sin(angle) * pwm_period;
   if (angle >=180) angle = 0;
   angle += 0.1;
}

static PWMConfig pwmcfg = {
  500000, /* 500Khz PWM clock frequency */
  pwm_period, /* PWM period 1 second */
  PwmCB,  /* callback */
  /* Only channel 4 enabled */
  {
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_DISABLED, NULL},
    {PWM_OUTPUT_ACTIVE_HIGH, NULL},
  },
  0
};

static msg_t pwm_switch(void *arg){
   while(1){
      //pwmDisableChannel(&PWMD4, 3);  //not shure, this is neccessary or not? works without this like a charm.
      pwmEnableChannel(&PWMD4, 3, pwm_duty);
   }
   return(0);
}



int main(void){
   Thread *tp ;
        halInit(); // initialize hardware abstraction layer
        chSysInit(); // initialize ChibiOS kernel

   palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL);
     palSetPadMode(GPIOD, 15, PAL_MODE_ALTERNATE(2));
   pwmStart(&PWMD4, &pwmcfg);
     pwmEnableChannel(&PWMD4, 3, 0);
   //Thread block:
   tp = chThdCreateStatic(pwm_ThreadWorkingArea,
                                 sizeof(pwm_ThreadWorkingArea),
                                 LOWPRIO,    /* Initial priority.    */
                                 pwm_switch,      /* Thread function.     */
                                 NULL);         /* Thread parameter.    */
        while(1){   
                        palSetPad(GPIOD, 13); // set GPIOD 15 low
                        chThdSleepMilliseconds(200);
                              palClearPad(GPIOD, 13); // set GPIOD 15 low
                        chThdSleepMilliseconds(200);
        }
}

Seems working.
What about using DAC output for sinus generation? It can be mapped to blink some leds or something?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: sinus emulation with pwm on stm43f4-discovery howto?

Post by Giovanni »

I-class functions are those whose name is terminated by an "I" and it is the only kind of functions you can call in ISrs and callbacks. You must also enclose them between chSysLockFromIsr() and chSysUnlockFromIsr().

Giovanni
Post Reply