Решено Непонятная работа HAL GPT в нескольких потоках

Тема в разделе "ChibiOS/RTOS", создана пользователем radioengineer, 17 июл 2015.

  1. radioengineer

    radioengineer Администратор Команда форума

    Сообщения:
    3.592
    Симпатии:
    357
    Адрес:
    Алматы
    Наткнулся на непонятный пока для меня баг в работе HAL GPT (General Purpose Timer). Ниже приведу код, а пока на словах, создаю 2 потока, в каждом завожу дергание ножкой с частотой 1кГц, задержку реализовал с помощью gptPolledDelay() драйвера GPT. Если поток один то проблем нет на осциллографе вижу нормальный меандр 1кГц. Но вот если 2 потока то получаю следующую картинку:

    pic_34_1.jpg pic_34_2.jpg

    Т.е. втыкается какая-то еще задержка, откуда она не понятно. На каждом потоке работает свой таймер для задержек, на одном Timer2, на другом Timer3

    PHP:
    #include "ch.h"
    #include "hal.h"

    #include <chprintf.h>

    static WORKING_AREA(waThread2128);
    static 
    msg_t Thread2(void *arg) {
        (
    void)arg;
        
    chRegSetThreadName("Ring1");
        while (
    TRUE) {
            
    moveRing1(TRUETRUE400150);
    }

    static 
    WORKING_AREA(waThread3128);
    static 
    msg_t Thread3(void *arg) {
        (
    void)arg;
        
    chRegSetThreadName("Ring2");
        while (
    TRUE) {
            
    moveRing2(TRUETRUE400150);
    }


    void moveRing1(bool_t enablebool_t diruint32_t stepsNumuint32_t period) {
        
    uint32_t count 0;
        if (
    enable != TRUE) {
            
    palSetPad(GPIOEGPIOE_INT2);        // if not enable set pin GPIOE.1, stop driver
        
    }
        else {
            
    palClearPad(GPIOEGPIOE_INT2);        // if enable clear pin GPIOE.1, start driver
        
    }
        if (
    dir == TRUE) {
            
    palSetPad(GPIOEGPIOE_PIN12);        // directory of rotary, DIR pin on Driver, GPIOE.12
        
    }
        else {
            
    palClearPad(GPIOEGPIOE_PIN12);
        }
        while(
    count stepsNum) {
            
    palSetPad(GPIOCGPIOC_PIN6);
            
    gptPolledDelay(&GPTD2period);
            
    palClearPad(GPIOCGPIOC_PIN6);
            
    gptPolledDelay(&GPTD2period);
            
    count ++;
        }
    }

    void moveRing2(bool_t enablebool_t diruint32_t stepsNumuint32_t period) {
        
    uint32_t count 0;
        if (
    enable != TRUE) {
            
    palSetPad(GPIOEGPIOE_PIN2);        // if not enable set pin GPIOE.1, stop driver
        
    }
        else {
            
    palClearPad(GPIOEGPIOE_PIN2);        // if enable clear pin GPIOE.1, start driver
        
    }
        if (
    dir == TRUE) {
            
    palSetPad(GPIOEGPIOE_PIN13);        // directory of rotary, DIR pin on Driver, GPIOE.12
        
    }
        else {
            
    palClearPad(GPIOEGPIOE_PIN13);
        }
        while(
    count stepsNum) {
            
    palSetPad(GPIOCGPIOC_MCLK);
            
    gptPolledDelay(&GPTD3period);
            
    palClearPad(GPIOCGPIOC_MCLK);
            
    gptPolledDelay(&GPTD3period);
            
    count ++;
        }
    }

    /*
    * GPT2 configuration.
    */
    static GPTConfig gpt2cfg =
    {
        
    300000,     /* timer clock.*/
        
    NULL        /* Timer callback.*/
    };

    /*
    * GPT3 configuration.
    */
    static GPTConfig gpt3cfg =
    {
        
    300000,     /* timer clock.*/
        
    NULL        /* Timer callback.*/
    };

    void ringInit() {
        
    palSetPadMode(GPIOEGPIOE_INT2PAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOEGPIOE_PIN12PAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOCGPIOC_PIN6PAL_MODE_OUTPUT_PUSHPULL); // step pin for ring 1

        
    palSetPadMode(GPIOEGPIOE_PIN2PAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOEGPIOE_PIN13PAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOCGPIOC_MCLKPAL_MODE_OUTPUT_PUSHPULL); // step pin for ring2

        
    palSetPadMode(GPIOEGPIOE_CS_SPIPAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOEGPIOE_PIN14PAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOBGPIOB_PIN0PAL_MODE_OUTPUT_PUSHPULL); // step pin for ring3

        
    palSetPadMode(GPIOEGPIOE_PIN4PAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOEGPIOE_PIN15PAL_MODE_OUTPUT_PUSHPULL);
        
    palSetPadMode(GPIOBGPIOB_PIN1PAL_MODE_OUTPUT_PUSHPULL); // step pin for ring3
    }

    // Application entry point.
    int main(void) {
        
    /*
         * System initializations.
         * - HAL initialization, this also initializes the configured device drivers
         *   and performs the board-specific initializations.
         * - Kernel initialization, the main() function becomes a thread and the
         *   RTOS is active.
         */
        
    halInit();
        
    chSysInit();
      
        
    /*
          * Activates the serial driver 2 using the driver default configuration.
            * PA2(TX) and PA3(RX) are routed to USART2.
            */
        /*sdStart(&SD2, NULL);
        palSetPadMode(GPIOA, 2, PAL_MODE_ALTERNATE(7));
        palSetPadMode(GPIOA, 3, PAL_MODE_ALTERNATE(7));*/

        
    ringInit();
        
    gptStart(&GPTD2, &gpt2cfg);
        
    gptStart(&GPTD3, &gpt3cfg);

        
    /*
         * Creates the example thread.
         */
        
    chThdCreateStatic(waThread2sizeof(waThread2), NORMALPRIOThread2NULL);
        
    chThdCreateStatic(waThread3sizeof(waThread3), NORMALPRIOThread3NULL);

        
    /*
         * Normal main() thread activity, in this demo it does nothing except
         * sleeping in a loop.
         */
        
    while (TRUE) {
            
    //chprintf((BaseSequentialStream *) &SD2, " %d\r", 101);      
            
    chThdSleepMilliseconds(1);     // Задержка для считывания новых данных, заменить на пин прерывания DRDY
        
    }
    }
    Последнее редактирование: 17 июл 2015
     
    : gpt, chibios, hal, timer
  2. radioengineer

    radioengineer Администратор Команда форума

    Сообщения:
    3.592
    Симпатии:
    357
    Адрес:
    Алматы
    Вот нормальная осциллограмма с одним потоком

    pic_35_1.jpg
  3. radioengineer

    radioengineer Администратор Команда форума

    Сообщения:
    3.592
    Симпатии:
    357
    Адрес:
    Алматы
    Создал темку на официальном форуме, посмотрим что ответят.
  4. radioengineer

    radioengineer Администратор Команда форума

    Сообщения:
    3.592
    Симпатии:
    357
    Адрес:
    Алматы
    В общем, Giovanni любезно ответил, что то что наблюдается в двух разных потоках есть не что иное как алгоритм Round Robin, т.е. функция gptPolledDelay() ест процессорное время, которое распределяется по задачам, каждая задача получает свой кусок процессорного времени, поэтому и выходит вот такая очередность работы таймера. Более подробно из википедии по алгоритму:
  5. radioengineer

    radioengineer Администратор Команда форума

    Сообщения:
    3.592
    Симпатии:
    357
    Адрес:
    Алматы
    Дядя Giovanni советует использовать chibios 3.0 с его функцией chThdSleepMicroseconds() и говорит, что не следует полагаться на тайминги потоков.

Поделиться этой страницей