Seeeduino XIAO считывает продолжительность (период) ШИМ, используя таймеры, которые меняют контакты с D2 на D1.

seeeduino-xiao

Я спроектировал печатную плату, и мне нужно проверить работоспособность. Поэтому мне нужно изменить код, чтобы он считывал данные с контактов D1, а не с D2. К сожалению, я не знаком с высокоуровневым программированием, поэтому я не уверен, что получил все изменения. В основном используются все PINS в цепи.

Базовый код можно найти здесь: Seeeduino XIAO записывает и читает длительность (период) ШИМ с помощью таймеров

Чтение коротких прямоугольных сигналов с выводом D2 Seeeduino XIAO

// Настройте TC4 для захвата ширины и периода импульса на цифровом выводе D2 на Seeeduino Xiao
volatile boolean periodComplete;
volatile uint32_t isrPeriod;
volatile uint32_t isrPulsewidth;
uint32_t period;
uint32_t pulsewidth;

void setup()   {                
  SerialUSB.begin(115200);                         // Инициализируем родной последовательный порт
  while(!SerialUSB);                               // ждем открытия консоли
  
  PM->APBCMASK.reg |= PM_APBCMASK_EVSYS;           // Включаем периферийное устройство системы событий

  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) |          // Делим системную частоту 48 МГц на 1 = 48 МГц
                     GCLK_GENDIV_ID(4);            // Установка деления на Generic Clock Generator (GCLK) 4

  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |           // Установите рабочий цикл на 50/50 ВЫСОКИЙ/НИЗКИЙ
                      GCLK_GENCTRL_GENEN |         // Включить GCLK 4
                      GCLK_GENCTRL_SRC_DFLL48M |   // Установите источник синхронизации на 48 МГц
                      GCLK_GENCTRL_ID(4);          // Установить источник синхронизации на GCLK 4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Ждем синхронизации
  
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Маршрутизируем GCLK4 к TC4 и TC5
                      GCLK_CLKCTRL_GEN_GCLK4 |     
                      GCLK_CLKCTRL_ID_TC4_TC5;     
  
  // Включить мультиплексор портов на выводе порта PA10
  PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
  // Настраиваем контакт как EIC (прерывание) на контакте порта PA10
  PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;

  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10;                                // Разрешить вывод события по внешнему прерыванию 10
  EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH;                            // Установить событие обнаружения ВЫСОКОГО уровня
  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10;                               // Отключить прерывания по внешнему прерыванию 10
  EIC->CTRL.reg |= EIC_CTRL_ENABLE;                                        // Включить периферийное устройство EIC
  while (EIC->STATUS.bit.SYNCBUSY);                                        // Ждем синхронизации
  
  EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) |                                // Прикрепляем пользователя события (получателя) к каналу 0 (n + 1)
                    EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU);                // Установить пользователя события (получателя) как таймер TC4

  EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                // Нет обнаружения фронта события
                       EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                   // Установить путь события как асинхронный
                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) |   // Установить генератор событий (отправитель) как внешнее прерывание 10
                       EVSYS_CHANNEL_CHANNEL(0);                           // Прикрепляем генератор (отправитель) к каналу 0

  TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI |               // Разрешить ввод события TC
                            //TC_EVCTRL_TCINV | // Инвертировать вход события
                            TC_EVCTRL_EVACT_PPW;           // Настраиваем таймер для захвата: период CC0, ширина импульса CC1
                  
  TC4->COUNT32.CTRLC.reg = TC_CTRLC_CPTEN1 |               // Включить захват на CC1
                           TC_CTRLC_CPTEN0;                // Включить захват на CC0
  while (TC4->COUNT32.STATUS.bit.SYNCBUSY);                // Ждем синхронизации

  NVIC_SetPriority(TC4_IRQn, 0);      // Установите приоритет Nested Vector Interrupt Controller (NVIC) для TC4 на 0 (самый высокий)
  NVIC_EnableIRQ(TC4_IRQn);           // Подключаем таймер TC4 к контроллеру вложенных векторных прерываний (NVIC)
 
  TC4->COUNT32.INTENSET.reg = TC_INTENSET_MC1 |            // Разрешить прерывания канала сравнения 1 (CC1)
                              TC_INTENSET_MC0;             // Разрешить прерывания канала сравнения 0 (CC0)
  
  TC4->COUNT32.CTRLA.reg = //TC_CTRLA_PRESCSYNC_PRESC | // Переполнение на часах предкалера (а не на GCLK)
                           TC_CTRLA_PRESCALER_DIV1  |      // Установите прескалер на 1, 48 МГц/1 = 48 МГц
                           TC_CTRLA_MODE_COUNT32;          // Установить TC4/TC5 в режим 32-битного таймера
                          
  TC4->COUNT32.CTRLA.bit.ENABLE = 1;                       // Включить TC4
  while (TC4->COUNT32.STATUS.bit.SYNCBUSY);                // Ждем синхронизации
}

void loop() { 
  if (periodComplete)                             // Проверяем, завершен ли период
  {
    noInterrupts();                               // Читаем новый период и длительность импульса
    period = isrPeriod;                  
    pulsewidth = isrPulsewidth;
    interrupts();
    SerialUSB.print("PW: ");
    SerialUSB.print(pulsewidth);
    SerialUSB.print(F("   "));
    SerialUSB.print("P: ");
    SerialUSB.println(period);
    periodComplete = false;                       // Начать новый период
  }
}

void TC4_Handler()                                // Процедура обслуживания прерывания (ISR) для таймера TC4
{    
  // Проверка совпадения счетчика 0 (MC0) прерывание
  if (TC4->COUNT32.INTFLAG.bit.MC0)            
  {
    TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ |           // Разрешить запрос на чтение
                               TC_READREQ_ADDR(0x18);      // Адрес смещения регистра CC0
    while (TC4->COUNT32.STATUS.bit.SYNCBUSY);              // Ожидание (чтение) синхронизации
    isrPeriod = TC4->COUNT32.CC[0].reg;                    // Копируем период
    periodComplete = true;                                 // Указываем, что период завершен
  }

  // Прерывание проверки совпадения счетчика 1 (MC1)
  if (TC4->COUNT32.INTFLAG.bit.MC1)          
  {
    TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ |           // Разрешить запрос на чтение
                               TC_READREQ_ADDR(0x1A);      // Адрес смещения регистра CC1
    while (TC4->COUNT32.STATUS.bit.SYNCBUSY);              // Ожидание (чтение) синхронизации
    isrPulsewidth = TC4->COUNT32.CC[1].reg;                // Копируем ширину импульса
  }
}

Мне нужно только изменить IO: от:
ПОРТ->Группа[PORTA].PINCFG[10].bit.PMUXEN = 1;
ПОРТ->Группа[ПОРТ].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
кому:
ПОРТ->Группа[PORTA].PINCFG[4].bit.PMUXEN = 1;
ПОРТ->Группа[ПОРТ].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;

или мне нужно модифицировать больше кода?

Спасибо за помощь.

, 👍0


1 ответ


Лучший ответ:

0

Помимо упомянутых вами изменений, ваши способы использования EIC_EVCTRL_EXTINTEO10, EIC_INTENCLR_EXTINT10 и EVSYS_ID_GEN_EIC_EXTINT_10 должны быть изменены на EIC_EVCTRL_EXTINTE4. , EIC_INTENCLR_EXTINT4 и на EVSYS_ID_GEN_EIC_EXTINT_4, чтобы перенацелить источник системы событий, поскольку PORT_PMUX_PMUXE_A на обоих эти контакты направляют сигнал на EIC, но не на точно такой же номер прерывания. Строка EIC->CONFIG должна измениться на первую группу из 8 ([0]) и четвертый SENSE в этой группе (EIC_CONFIG_SENSE4_HIGH ) к изменению на D1 (PA04) использует EXTINT4. Это то, что я упустил из первого редактирования, прежде чем смог протестировать. В конце концов я нашел XIAO для тестирования, и эти модификации, кажется, теперь позволяют ему нормально работать на цифровом контакте 1 вместо цифрового контакта 2.

EIC->EVCTRL.reg    |= EIC_EVCTRL_EXTINTE4;
EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;
EIC->INTENCLR.reg   = EIC_INTENCLR_EXTINT4;
EIC->CTRL.reg      |= EIC_CTRL_ENABLE;
while (EIC->STATUS.bit.SYNCBUSY);

...

EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                
                     EVSYS_CHANNEL_PATH_ASYNCHRONOUS |
                     EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) |
                     EVSYS_CHANNEL_CHANNEL(0);

Изменения, о которых вы упомянули, и те, которые я назвал выше как различия:

--- original.ino
+++ modified.ino
@@ -24,14 +24,14 @@
                       GCLK_CLKCTRL_GEN_GCLK4 |     
                       GCLK_CLKCTRL_ID_TC4_TC5;     
   
-  // Включить мультиплексор портов на выводе порта PA10
-  PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
-  // Настраиваем вывод как EIC (прерывание) на выводе порта PA10
-  PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
+  // Включить мультиплексор портов на выводе порта PA04
+  PORT->Group[PORTA].PINCFG[4].bit.PMUXEN = 1;
+  // Настройте контакт как EIC (прерывание) на контакте порта PA04
+  PORT->Group[PORTA].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;
 
-  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10;                                // Разрешить вывод события по внешнему прерыванию 10
-  EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH;                            // Установить событие обнаружения ВЫСОКОГО уровня
-  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10;                               // Отключить прерывания по внешнему прерыванию 10
+  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO4;                                 // Разрешить вывод события по внешнему прерыванию 4
+  EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;                            // Установить событие обнаружения ВЫСОКОГО уровня
+  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT4;                                // Отключить прерывания по внешнему прерыванию 4
   EIC->CTRL.reg |= EIC_CTRL_ENABLE;                                        // Включить периферийное устройство EIC
   while (EIC->STATUS.bit.SYNCBUSY);                                        // Ждем синхронизации
   
@@ -40,7 +40,7 @@
 
   EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                // Нет обнаружения фронта события
                        EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                   // Установить путь события как асинхронный
-                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) |   // Установить генератор событий (отправитель) как внешнее прерывание 10
+                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) |    // Установить генератор событий (отправитель) как внешнее прерывание 4
                        EVSYS_CHANNEL_CHANNEL(0);                           // Прикрепляем генератор (отправитель) к каналу 0
 
   TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI |               // Разрешить ввод события TC
,