Page 1 of 1
sinus emulation with pwm on stm43f4-discovery howto?
Posted: Wed Mar 26, 2014 6:22 pm
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!
Re: sinus emulation with pwm on stm43f4-discovery howto?
Posted: Wed Mar 26, 2014 7:28 pm
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
Re: sinus emulation with pwm on stm43f4-discovery howto?
Posted: Wed Mar 26, 2014 10:08 pm
by pito
You may generate the sinus directly via DAC.
Re: sinus emulation with pwm on stm43f4-discovery howto?
Posted: Wed Mar 26, 2014 11:18 pm
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.
Re: sinus emulation with pwm on stm43f4-discovery howto?
Posted: Thu Mar 27, 2014 10:09 am
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?
Re: sinus emulation with pwm on stm43f4-discovery howto?
Posted: Thu Mar 27, 2014 10:16 am
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
Re: sinus emulation with pwm on stm43f4-discovery howto?
Posted: Fri Mar 28, 2014 10:32 am
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?
Re: sinus emulation with pwm on stm43f4-discovery howto?
Posted: Fri Mar 28, 2014 10:48 am
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