Page 1 of 1

a project with pwm and adc

Posted: Fri Dec 29, 2017 10:25 am
by XXzzz
I use the pwm to control the motor and adc to get Sampling current.
1.in pwm chanel callback

Code: Select all

static void pwmc1cb(PWMDriver *pwmp)
{
  (void)pwmp;

  chSysLockFromISR();

  adcStartConversionI(&ADCD1, &adcgrpcfg, samples, ADC_GRP_BUF_DEPTH);

  chSysUnlockFromISR();

}


2. in adc callback

Code: Select all

static void adccallback(ADCDriver *adcp, adcsample_t *buffer, size_t n)
{
  (void)adcp;
  (void)buffer;
  (void)n;

  chSysLockFromISR();
  adcStopConversionI(&ADCD1);
  chBSemSignalI(&current_bsem);
  chSysUnlockFromISR();

}

3. create a thread to get the samples after signall

Code: Select all

static THD_WORKING_AREA(waThread2, 128);
static THD_FUNCTION(Thread2, arg)
{
  (void)arg;
  chRegSetThreadName("current");
  while (true)
  {
    msg_t msg = chBSemWait(&current_bsem);
    (void)msg;
    float ret = getCurrent(motor1.state);
    (void)ret;
  }
}

(getCurrent can get adc samples and transform it to current)
now the thread doesn't work ,mabe i need use other way to get the current on PWM_ACTIVE voltage?

Re: a project with pwm and adc

Posted: Fri Dec 29, 2017 10:35 am
by Giovanni
Is the semaphore initialized to "taken"?

You should consider HW triggering for the ADC, it would perform a continuous circular conversion triggered by the PWM timer. You need to verify if your timer is one of the possible trigger sources for ADC.

Also, is it worth using a thread for this? simple processing could be done directly in the ADC callback.

Giovanni

Re: a project with pwm and adc

Posted: Fri Dec 29, 2017 11:10 am
by XXzzz
now i change my code to test my callback ,clear the light in callback ,and set the light in thread ,and callback is working,

Code: Select all

static void pwmc1cb(PWMDriver *pwmp)
{
  (void)pwmp;

  chSysLockFromISR();
  adcStartConversionI(&ADCD1, &adcgrpcfg, samples, ADC_GRP_BUF_DEPTH);
  chSysUnlockFromISR();
  palClearPad(GPIOG, GPIOG_LED_2);
}

static void adccallback(ADCDriver *adcp, adcsample_t *buffer, size_t n)
{
  (void)adcp;
  (void)buffer;
  (void)n;

  chSysLockFromISR();
  adcStopConversionI(&ADCD1);
  chBSemSignalI(&current_bsem);
  chSysUnlockFromISR();
  palClearPad(GPIOG, GPIOG_LED_3);
}

static THD_WORKING_AREA(waThread2, 128);
static THD_FUNCTION(Thread2, arg)
{
  (void)arg;
  chRegSetThreadName("current");
  while (true)
  {
    msg_t msg = chBSemWait(&current_bsem);
    (void)msg;
    float ret = getCurrent(motor1.state);
    (void)ret;
  }
}

static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg)
{
  (void)arg;
  chRegSetThreadName("blinker");
  while (true)
  {
    palSetPad(GPIOG, GPIOG_LED_2);
    palSetPad(GPIOG, GPIOG_LED_3);
   
    palSetPad(GPIOB, GPIOB_LED_1);
    chThdSleepMilliseconds(500);
    palClearPad(GPIOB, GPIOB_LED_1);
    chThdSleepMilliseconds(500);
  }
}


i also have some info to print in the getCurrent()
and chBSemObjectInit(&current_bsem, TRUE); been call after the pwm init
so it willbe like this pwm init->sem init->adc init ->pwm output->pwm callback->adc start Conversion ->adc callback->signal and adc stop Conversion ->getCurrent in the thread. and pwm call back will run again
so i can get the current in the active voltage,
and now the thread is running ,and the pwm callback ,adc callback also working ,but the thread seem can't recv the signal

Re: a project with pwm and adc

Posted: Fri Dec 29, 2017 12:17 pm
by XXzzz
now i do a new test on stm32f103zet6

Code: Select all


#include <stdio.h>
#include <string.h>

#include "ch.h"
#include "hal.h"
#include "ch_test.h"
#include "usbcfg.h"
#include "myshell.h"

#define SHELL_WA_SIZE THD_WORKING_AREA_SIZE(2048)
binary_semaphore_t bsem;

static void pwmpcb(PWMDriver *pwmp)
{
  (void)pwmp;
  palSetPad(GPIOB, GPIOB_LED_1);
  chSysLockFromISR();
  chBSemSignalI(&bsem);
  chSysUnlockFromISR();
}

static void pwmc1cb(PWMDriver *pwmp)
{

  (void)pwmp;
  palClearPad(GPIOB, GPIOB_LED_1);
  chSysLockFromISR();
  chBSemSignalI(&bsem);
  chSysUnlockFromISR();
}

static PWMConfig pwmcfg = {
    1000,
    10000, //pwm 10s
    pwmpcb,
    {{PWM_OUTPUT_ACTIVE_HIGH, pwmc1cb},
     {PWM_OUTPUT_DISABLED, NULL},
     {PWM_OUTPUT_DISABLED, NULL},
     {PWM_OUTPUT_DISABLED, NULL}},
    0,
    0,
#if STM32_PWM_USE_ADVANCED
    0
#endif
};

/*
 * blinker
 */
static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg)
{
  (void)arg;
  chRegSetThreadName("blinker");
  while (true)
  {
    msg_t msg = chBSemWait(&bsem);
    palClearPad(GPIOG, GPIOG_LED_2);
    (void)msg;
  }
}

int main(void)
{

  halInit();
  chSysInit();

  //Bsem  init
  chBSemObjectInit(&bsem, TRUE);
  /*
   * pwm init
   */
  pwmStart(&PWMD1, &pwmcfg);
  pwmEnablePeriodicNotification(&PWMD1);
  palSetPadMode(IOPORT1, 8, PAL_MODE_STM32_ALTERNATE_PUSHPULL); /*PA8*/

  /*
   * 75%
   */
  pwmEnableChannel(&PWMD1, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD1, 7500));
  pwmEnableChannelNotification(&PWMD1, 0);
  chThdSleepMilliseconds(500000);

  /*
   * stop pwm
   */
  pwmDisableChannel(&PWMD1, 0);
  pwmStop(&PWMD1);

  /*
   * creat blinker thread
   */
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);

  while (true)
  {
  }
}


and the led1 has been set and clear in the callback but the led2 not been clear,
i think the thread dosn't recv the signal.
and the code about sem are right?

Re: a project with pwm and adc

Posted: Fri Dec 29, 2017 2:25 pm
by Giovanni
Hi,

That empty while in your main(), it does not release CPU for other threads at equal or lower priority. Put a chThdSleep() in there.

Giovanni

Re: a project with pwm and adc

Posted: Sun Dec 31, 2017 10:23 am
by XXzzz
now i change the thread to this

Code: Select all

static THD_WORKING_AREA(waThread2, 128);
static THD_FUNCTION(Thread2, arg)
{
  (void)arg;
  chRegSetThreadName("current");
  while (true)
  {
    msg_t msg = chBSemWaitTimeout(&current_bsem, MS2ST(500));
    /* time out*/
    if (msg == MSG_TIMEOUT)
    {
      chprintf((BaseSequentialStream *)&SD2, "\r\ncurrent thread timeout\r\n");
      continue;
    }
    float ret = getCurrent(motor1.state);
    chThdSleepMilliseconds(500);
  }
}

and it's working , maybe the reason is when pwminit->adcinit->creatthread
this thread is blocked and wait for a Bsem and it's blocked too much time .
but i can't understand :why it can't work ? i think it could wait and get the sem
and this thraed use chBSemWaitTimeout() seems just not blocked.
i want know why ,maybe i need learn more about the Priorities and Scheduling or how does the scheduler work?

Re: a project with pwm and adc

Posted: Sun Dec 31, 2017 10:57 am
by Giovanni
The rule is very simple and is valid for most RTOSes:

Among the threads not sleeping/waiting, the one with highest priority is the being executed.

A thread not releasing CPU is going to block all other threads to equal or lower priority.

Giovanni

Re: a project with pwm and adc

Posted: Sun Dec 31, 2017 2:24 pm
by XXzzz
now my code has another bug..,
when i set the depth=8,and the callback return the n =4,
depth=16,n=8;
this is my test code ,it work like pwmstart->pwmcallback->adcStartConversion->adccallback->Bsem->thread
then the thread print the samples buffer and n.

Code: Select all


#include <stdio.h>
#include <string.h>

#include "ch.h"
#include "hal.h"
#include "ch_test.h"

#include "myshell.h"

#define CHP ((BaseSequentialStream *)&SD2)
#define SHELL_WA_SIZE THD_WORKING_AREA_SIZE(2048)
#define ADC_GRP_NUM_CHANNELS 3 //adc 通道数
#define ADC_GRP_BUF_DEPTH 16   //数据深度

int samplessize = 0;
binary_semaphore_t bsem, errsem;
adcsample_t samples[ADC_GRP_NUM_CHANNELS * ADC_GRP_BUF_DEPTH]; //buffer

/**
 * @brief       ADC
 *
 */
static void adccallback(ADCDriver *adcp, adcsample_t *buffer, size_t n)
{
  (void)adcp;
  (void)buffer;
  (void)n;
  //锁定进入isr
  chSysLockFromISR();
  samplessize = n;
  chBSemSignalI(&bsem); //发送信号

  adcStopConversionI(&ADCD1); //停止adc转换
  //解锁
  chSysUnlockFromISR();
}

static void adcerrorcallback(ADCDriver *adcp, adcerror_t err)
{
  (void)adcp;
  (void)err;
  chSysLockFromISR();

  // chBSemSignalI(&errsem); //发送信号

  chSysUnlockFromISR();
  palClearPad(GPIOB, GPIOB_LED_1);
}

const ADCConversionGroup adcgrpcfg = {
    TRUE,
    ADC_GRP_NUM_CHANNELS,
    adccallback,
    adcerrorcallback,
    0,
    ADC_CR2_TSVREFE, /*  CR2 */
    ADC_SMPR1_SMP_VREF(ADC_SAMPLE_239P5) | ADC_SMPR1_SMP_AN11(ADC_SAMPLE_239P5) | ADC_SMPR1_SMP_AN10(ADC_SAMPLE_239P5),
    0, /* SMPR2 */
    ADC_SQR1_NUM_CH(ADC_GRP_NUM_CHANNELS),
    0,
    ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT) | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN10) | ADC_SQR3_SQ3_N(ADC_CHANNEL_IN11)};

/**
 * @brief       PWM
 *
 */
static void pwmpcb(PWMDriver *pwmp)
{
  (void)pwmp;
}

static void pwmc1cb(PWMDriver *pwmp)
{

  (void)pwmp;

  chSysLockFromISR();
  // chBSemSignalI(&bsem);
  adcStartConversion(&ADCD1, &adcgrpcfg, samples, ADC_GRP_BUF_DEPTH);
  chSysUnlockFromISR();
}

static PWMConfig pwmcfg = {
    100000,
    1000, //pwm 10s
    pwmpcb,
    {{PWM_OUTPUT_ACTIVE_HIGH, pwmc1cb},
     {PWM_OUTPUT_DISABLED, NULL},
     {PWM_OUTPUT_DISABLED, NULL},
     {PWM_OUTPUT_DISABLED, NULL}},
    0,
    0,
#if STM32_PWM_USE_ADVANCED
    0
#endif
};

/*
 * blinker
 */
static THD_WORKING_AREA(waThread1, 128);
static THD_FUNCTION(Thread1, arg)
{
  (void)arg;
  chRegSetThreadName("blinker");
  while (true)
  {
    msg_t msg = chBSemWaitTimeout(&bsem, MS2ST(1000));
    /* time out*/
    if (msg == MSG_TIMEOUT)
    {
      chprintf((BaseSequentialStream *)&SD2, "\r\ncurrent thread timeout\r\n");
      continue;
    }
    chprintf((BaseSequentialStream *)&SD2, "samples size=%d\r\n", samplessize);
    for (int i = 0; i < ADC_GRP_NUM_CHANNELS; i++)
    {
      for (int j = 0; j < ADC_GRP_BUF_DEPTH; j++)
        chprintf((BaseSequentialStream *)&SD2, "%d\t", samples[i + j * ADC_GRP_NUM_CHANNELS]);
      chprintf((BaseSequentialStream *)&SD2, "\r\n");
    }
    chprintf((BaseSequentialStream *)&SD2, "\r\n\r\n");
  }
}

int main(void)
{

  halInit();
  chSysInit();
  shellInit();
  sdStart(&SD2, NULL);
  //Bsem  init
  chBSemObjectInit(&bsem, TRUE);
  // chBSemObjectInit(&errsem, TRUE);

  /*
   * pwm init
   */
  pwmStart(&PWMD1, &pwmcfg);
  pwmEnablePeriodicNotification(&PWMD1);
  palSetPadMode(IOPORT1, 8, PAL_MODE_STM32_ALTERNATE_PUSHPULL); /*PA8*/
  /*
   * adc init
   */
  //1.初始化GPIO
  palSetGroupMode(GPIOC, PAL_PORT_BIT(0) | PAL_PORT_BIT(1),
                  0, PAL_MODE_INPUT_ANALOG);
  //2.开启adc
  adcStart(&ADCD1, NULL);

  /*
   * 75%
   */
  pwmEnableChannel(&PWMD1, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD1, 7500));
  pwmEnableChannelNotification(&PWMD1, 0);
  // chThdSleepMilliseconds(500000);

  /*
   * stop pwm
   */
  // pwmDisableChannel(&PWMD1, 0);
  // pwmStop(&PWMD1);

  /*
   * creat blinker thread
   */
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);

  while (true)
  {

    thread_t *shelltp = chThdCreateFromHeap(NULL, SHELL_WA_SIZE,
                                            "shell", NORMALPRIO + 1,
                                            shellThread, (void *)&shell_cfg1);
    chThdWait(shelltp); /* Waiting termination.             */

    chThdSleepMilliseconds(1000);
  }
}

this is print data

Code: Select all

//when adc depth=8
samples size=4
1507   1507   1509   1508   0   0   0   0   
0   0   0   7   0   0   0   0   
0   0   5   8   0   0   0   0
//when adc depth=16
samples size=8
1508   1508   1509   1509   1509   1509   1509   1510   0   0   0   0   0   0   0   0   
3   0   6   53   0   0   0   0   0   0   0   0   0   0   0   0   
7   4   0   6   0   0   0   0   0   0   0   0   0   0   0   0   


i read the doc again ,in the Driver State Machine, maybe the callback will be called twice:once is half and another is full?

Re: a project with pwm and adc

Posted: Sun Dec 31, 2017 3:46 pm
by Giovanni
The callback is called twice for circular conversions, you are doing a circular conversion there. One callback at half buffer another one at the end.

Giovanni

Re: a project with pwm and adc

Posted: Mon Jan 01, 2018 9:00 am
by XXzzz
i got that.That's a really good way to do it. I need pay more attention to the doc.thanks again