Stellaris IMU. Захват PWM

Начинал писать этот пост, когда уже совсем запутался в таймерах и прерываниях stellaris LM4F120H5QR, в попытках осуществить захват входящих PWM сигналов и определить длину импульса. Признаться я так и не понял, как заставить сам таймер считать в промежутках между растущим и ниспадающим фронтами. Поэтому пришлось ловить сигнал таким образом: при смене уровня на пине генерируется прерывание, проверяется уровень на входе и в соответствие с этим либо запускается таймер, либо останавливается и записывается длина импульса. Но эта идея (лежащая, практически на поверхности) пришла ко мне после долгих поисков и тупиковых путей, хотя начинал я осваивать прерывания именно с этого.

Итак, для захвата двух каналов PWM мне понадобились обе половинки одного таймера (использую TIMER2), TIMER_A и TIMER_B сконфигурированы на периодический счет таким образом:

SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
TimerConfigure(TIMER2_BASE,
TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PERIODIC|TIMER_CFG_B_PERIODIC);
TimerPrescaleSet(TIMER2_BASE, TIMER_A, SysCtlClockGet()/1000000);
TimerPrescaleSet(TIMER2_BASE, TIMER_B, SysCtlClockGet()/1000000);
TimerLoadSet(TIMER2_BASE, TIMER_A, SysCtlClockGet()/ 20);
TimerLoadSet(TIMER2_BASE, TIMER_B, SysCtlClockGet()/ 20);
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
TimerConfigure(TIMER2_BASE,
TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PERIODIC|TIMER_CFG_B_PERIODIC);
TimerPrescaleSet(TIMER2_BASE, TIMER_A, SysCtlClockGet()/1000000);
TimerPrescaleSet(TIMER2_BASE, TIMER_B, SysCtlClockGet()/1000000);
TimerLoadSet(TIMER2_BASE, TIMER_A, SysCtlClockGet()/ 20);
TimerLoadSet(TIMER2_BASE, TIMER_B, SysCtlClockGet()/ 20);

Это обеспечивает значения таймеров при минимальной длине импульса с выхода приемника РУ — 400, максимальное — 1200. Как настроить на стандартные для сервомашинок и регуляторов БК моторов 1000..2000 мс, не могу сообразить, если кто может посоветовать, буду благодарен.) Выводы PC6, PC7 (а в будущем и PC4, PC5) инициализируются как входы и настроены на генерацию прерываний при смене уровня входного сигнала:

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
GPIOPinTypeGPIOInput(GPIO_PORTC_BASE, GPIO_PIN_6|GPIO_PIN_7);
        GPIOPadConfigSet(GPIO_PORTC_BASE,
GPIO_PIN_6|GPIO_PIN_7,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);
GPIOIntTypeSet(GPIO_PORTC_BASE, GPIO_PIN_6|GPIO_PIN_7, GPIO_BOTH_EDGES);
GPIOPinIntEnable(GPIO_PORTC_BASE, GPIO_PIN_6|GPIO_PIN_7);
 GPIOPortIntRegister(GPIO_PORTC_BASE,IntGPIOc);
        IntMasterEnable();
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
GPIOPinTypeGPIOInput(GPIO_PORTC_BASE, GPIO_PIN_6|GPIO_PIN_7);
		GPIOPadConfigSet(GPIO_PORTC_BASE,
GPIO_PIN_6|GPIO_PIN_7,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);
GPIOIntTypeSet(GPIO_PORTC_BASE, GPIO_PIN_6|GPIO_PIN_7, GPIO_BOTH_EDGES);
GPIOPinIntEnable(GPIO_PORTC_BASE, GPIO_PIN_6|GPIO_PIN_7);
 GPIOPortIntRegister(GPIO_PORTC_BASE,IntGPIOc);
		IntMasterEnable();

Где IntGPIOc — обработчик прерывания, который выглядит следующим образом:

void IntGPIOc(void)
{
  // выясняем на каком пине произошло прерывание
  unsigned long status = GPIOPinIntStatus(GPIO_PORTC_BASE, true);
  switch (status) {
   // если пин PC6
   case 0x00000040: {GPIOPinIntClear(GPIO_PORTC_BASE, GPIO_PIN_6);
    // проверяем уровень на входе, если высокий. то
    if (GPIOPinRead( GPIO_PORTC_BASE, GPIO_PIN_6)) {
     //устанавливаем периодичность счета таймера B
     TimerLoadSet(TIMER2_BASE, TIMER_B, SysCtlClockGet()/20);
     // запускаем таймер B
     TimerEnable(TIMER2_BASE, TIMER_B);
    } else {
     // если низкий, то присваиваем переменной значение таймера
     Throttle_pulse = TimerValueGet(TIMER2_BASE,TIMER_B );
     // останавливаем таймер
     TimerDisable(TIMER2_BASE, TIMER_B);
    }
    break;}
   // если пин PC67
   case 0x00000080: {GPIOPinIntClear(GPIO_PORTC_BASE, GPIO_PIN_7);
    if (GPIOPinRead( GPIO_PORTC_BASE, GPIO_PIN_7)) {
     //устанавливаем периодичность счета таймера A
     TimerLoadSet(TIMER2_BASE, TIMER_A, SysCtlClockGet()/20);
     // запускаем таймер A
     TimerEnable(TIMER2_BASE, TIMER_A);
    } else {
     // если низкий, то присваиваем переменной значение таймера
     Roll_pulse = TimerValueGet(TIMER2_BASE,TIMER_A );
      // останавливаем таймер
     TimerDisable(TIMER2_BASE, TIMER_A);
    }
   break;}
 }
}
void IntGPIOc(void)
{
  // выясняем на каком пине произошло прерывание
  unsigned long status = GPIOPinIntStatus(GPIO_PORTC_BASE, true);
  switch (status) {
   // если пин PC6
   case 0x00000040: {GPIOPinIntClear(GPIO_PORTC_BASE, GPIO_PIN_6);
    // проверяем уровень на входе, если высокий. то
    if (GPIOPinRead( GPIO_PORTC_BASE, GPIO_PIN_6)) {
     //устанавливаем периодичность счета таймера B
     TimerLoadSet(TIMER2_BASE, TIMER_B, SysCtlClockGet()/20);
     // запускаем таймер B
     TimerEnable(TIMER2_BASE, TIMER_B);
    } else {
     // если низкий, то присваиваем переменной значение таймера
     Throttle_pulse = TimerValueGet(TIMER2_BASE,TIMER_B );
     // останавливаем таймер
     TimerDisable(TIMER2_BASE, TIMER_B);
    }
    break;}
   // если пин PC67
   case 0x00000080: {GPIOPinIntClear(GPIO_PORTC_BASE, GPIO_PIN_7);
    if (GPIOPinRead( GPIO_PORTC_BASE, GPIO_PIN_7)) {
     //устанавливаем периодичность счета таймера A
     TimerLoadSet(TIMER2_BASE, TIMER_A, SysCtlClockGet()/20);
     // запускаем таймер A
     TimerEnable(TIMER2_BASE, TIMER_A);
    } else {
     // если низкий, то присваиваем переменной значение таймера
     Roll_pulse = TimerValueGet(TIMER2_BASE,TIMER_A );
      // останавливаем таймер
     TimerDisable(TIMER2_BASE, TIMER_A);
    }
   break;}
 }
}

Перед запуском таймера, приходится постоянно выполнять  TimerLoadSet(), иначе счет идет не корректно (как точно, уже не помню). Это был крайний ключевой момент, который нужно было освоить, и теперь можно переходить к наземным  тестам на трикоптере. В следующий раз об этом и расскажу.)

Запись опубликована в рубрике ARM, Разработки, Трикоптер. Добавьте в закладки постоянную ссылку.

         
Подписаться на новые статьи блога:

2 комментария: Stellaris IMU. Захват PWM

  1. google.com Sergey Gimaev говорит:

    коллега, купи приемник с s-bus в очередной раз говорю. УАРТ проще грабить нежели РРМ еще и поканально. столько гимора сразу пропадет.
    вот например http://www.hobbyking.com/hobbyking/store/__24785__FrSky_TFR8_SB_8ch_2_4Ghz_S_BUS_Receiver_FASST_Compatible.html

  2. Delirium говорит:

    Голь на выдумки хитра и трудности, как правило не пугают.) В этом деле, хочу обойтись тем, что есть в наличии. А приемник — гуд.)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.