Можно ли подсчитать нарастающие фронты тактового сигнала 4 МГц на Arduino Due и вызвать прерывание, как все 4 000 000 фронтов?

У меня проблемы с Arduino Due и функциональностью счетчика таймера. Вот чего я пытаюсь достичь:

Я хочу выполнить функцию в определенный момент времени или более точно после определенного количества нарастающих фронтов, заданных внешним тактовым сигналом с частотой прибл. 4 МГц. Таким образом, я прочитал таблицу данных Atmel, раздел 36, счетчик таймера. Мой подход заключался в том, чтобы вызывать прерывание при каждом нарастающем фронте и увеличивать переменную счетчика до тех пор, пока я не достигну желаемого количества нарастающих фронтов, а затем вызывать свою функцию. Я могу подтвердить, что на самом деле я считаю нарастающие фронты с моим текущим подходом, но я читаю слишком медленно. Есть ли какой-либо регистр или аппаратный счетчик, который автоматизирует процесс подсчета? Например, я устанавливаю в регистре определенное значение и жду переполнения, выполняю свою функцию и сбрасываю регистр? Из моего веб-исследования я обнаружил, что это возможно на Uno и Mega, но я не смог ничего найти для Due, и, честно говоря, я немного ошеломлен таблицей данных Atmel. Почему бы тогда просто не использовать Arduino Due или Mega? Мне нужны 3,3 вольта для Due, и из того, что я нашел, Uno и Mega - это устройства на 5 вольт.

Это мой код:

// определяем каналы захвата
#define CAPTURE_TC TC0
# определить CAPTURE_CHANNEL 0
#define CAPTURE_IRQn TC0_IRQn
#define CAPTURE_Handler TC0_Handler
#define CAPTURE_ID ID_TC0
#define CAPTURE_PIN 2
#define CAPTURE_CLOCK_SELECTION TC_CMR_TCCLKS_TIMER_CLOCK3

// делители часов, соответствующие CAPTURE_CLOCK_SELECTION
статическая константа 32_t divisors[5] = { 2, 8, 32, 128, 0};

volatile uint32_t захваченные_импульсы = 0;
изменчивый uint32_t захваченный_ra = 0;
изменчивый uint32_t захваченный_rb = 0;
переменная частота с плавающей запятой, duty_cycle, active_time;

/*
* Функция: настройка
* -------------------------------------------------- -----------------------------
* Код установки. Будет выполнен один раз.
*/
недействительная установка () {

// инициируем последовательное соединение
Серийный.начать(115200);
Serial.print("Инициализация...");

// настроить вывод PIO как периферийный
const PinDescription *config = &g_APinDescription[CAPTURE_PIN];
PIO_Configure(config->pPort, config->ulPinType, config->ulPin, config->ulPinConfiguration);

// включить периферийные часы таймера
pmc_enable_periph_clk(CAPTURE_ID);

// настроить таймер
TC_Configure(CAPTURE_TC, CAPTURE_CHANNEL,
CAPTURE_CLOCK_SELECTION // Выбор часов
| TC_CMR_LDRA_RISING // Загрузка RA: нарастающий фронт TIOA
| TC_CMR_LDRB_FALLING // Загрузка RB: задний фронт TIOA
| TC_CMR_ABETRG // Внешний триггер: TIOA
| TC_CMR_ETRGEDG_FALLING // Внешний фронт триггера: спадающий фронт
);

// настроить прерывания TC
NVIC_DisableIRQ(CAPTURE_IRQn);
NVIC_ClearPendingIRQ(CAPTURE_IRQn);
NVIC_SetPriority(CAPTURE_IRQn, 0);
NVIC_EnableIRQ(CAPTURE_IRQn);

// разрешаем прерывания
CAPTURE_TC->TC_CHANNEL[CAPTURE_CHANNEL].TC_IER = TC_IER_LDRBS;

// запускаем счетчик таймера
CAPTURE_TC->TC_CHANNEL[CAPTURE_CHANNEL].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;

Serial.println("Готово!");

} // настраивать

/*
* Функция: петля
* -------------------------------------------------- -----------------------------
* Циклический код. Будет выполняться повторно после завершения установки.
*/
недействительный цикл () {

// Serial.print("Захвачены нарастающие фронты: "); Serial.println(captured_ra);
} // петля

/*
* Функция: CAPTURE_Handler
* -------------------------------------------------- -----------------------------
*
*/
недействительным CAPTURE_Handler () {
если ((TC_GetStatus(CAPTURE_TC, CAPTURE_CHANNEL) и TC_SR_LDRBS) == TC_SR_LDRBS) {
захваченные_импульсы++;
// Capture_ra = CAPTURE_TC->TC_CHANNEL[CAPTURE_CHANNEL].TC_RA;
// Capture_rb = CAPTURE_TC->TC_CHANNEL[CAPTURE_CHANNEL].TC_RB;

если (захваченные_импульсы == 4164303) {
захваченные_импульсы = 0;
// конкретная_функция_вызов();
}
}
} // CAPTURE_Handler

Спасибо за ваше время, мы очень ценим любую помощь.

, 👍0


1 ответ


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

2

Прежде всего извините меня за бездействие, но, как вы знаете, сейчас сумасшедшие времена. Однако я, наконец, понял это, это, конечно, не самое элегантное решение, но оно соответствует моим требованиям. Спасибо за помощь @KamilCuk.

Вот мой код, если у кого-нибудь может возникнуть такая же проблема, как у меня. Внешний сигнал поступает на цифровой контакт 2. Отлично работает с внешним тактовым генератором 4,2 МГц.

// определяем каналы захвата
#define CAPTURE_TC TC0
# определить CAPTURE_CHANNEL 0
#define CAPTURE_IRQn TC0_IRQn
#define CAPTURE_Handler TC0_Handler
#define CAPTURE_ID ID_TC0
#define CAPTURE_PIN 2
#define CAPTURE_CLOCK_SELECTION TC_CMR_TCCLKS_TIMER_CLOCK3

/*
* Функция: настройка
* -------------------------------------------------- -----------------------------
* Код установки. Будет выполнен один раз.
*/
недействительная установка () {

// инициируем последовательное соединение
Серийный.начать(115200);
Serial.print("Инициализация...");

// настроить вывод PIO как периферийный
const PinDescription *config = &g_APinDescription[CAPTURE_PIN];
PIO_Configure(config->pPort, config->ulPinType, config->ulPin, config->ulPinConfiguration);

// включить периферийные часы таймера
pmc_enable_periph_clk(CAPTURE_ID);

// настроить таймер
TC_Configure(CAPTURE_TC, CAPTURE_CHANNEL,
CAPTURE_CLOCK_SELECTION // Выбор часов
| TC_CMR_LDRA_RISING // Загрузка RA: нарастающий фронт TIOA
| TC_CMR_ABETRG // Внешний триггер: TIOA
| TC_CMR_CPCTRG // Сравнение RC
);

// настроить прерывания TC
NVIC_DisableIRQ(CAPTURE_IRQn);
NVIC_ClearPendingIRQ(CAPTURE_IRQn);
NVIC_SetPriority(CAPTURE_IRQn, 0);

// разрешаем прерывания и запускаем счетчик
CAPTURE_TC->TC_CHANNEL[CAPTURE_CHANNEL].TC_IER = TC_IER_CPCS; // включить прерывание сравнения RC
CAPTURE_TC->TC_CHANNEL[CAPTURE_CHANNEL].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // в даташите сказано, что мне это нужно
NVIC_EnableIRQ(CAPTURE_IRQn); // разрешаем прерывания

// устанавливаем значение триггера для RC_Compare
CAPTURE_TC->TC_CHANNEL[CAPTURE_CHANNEL].TC_RC = 4164303;

Serial.println("Готово!");

} // настраивать


/*
* Функция: петля
* -------------------------------------------------- -----------------------------
* Основной код. Будет выполняться неоднократно.
*/
недействительный цикл () {

} // петля


/*
* Функция: CAPTURE_Handler соответственно TC0_Handler
* -------------------------------------------------- -----------------------------
* Триггер захвата таймера. Будет выполнено, если TC0_RA == TC0_RC
*/
недействительным CAPTURE_Handler () {
// сброс регистра состояния
TC_GetStatus(CAPTURE_TC, CAPTURE_CHANNEL);

// сделай что-нибудь
Serial.println("Триггер");
// функция_вызов()
}
,