как запустить RTT таймер на DUE

saer
Offline
Зарегистрирован: 12.05.2014

Добрый!

Помогите!, как запустить RTT таймер?

Условие: 1 раз в секунду запускать  prc()

DueTimer не подходит.

Оказывается , она конфликтует с LiquidCrystal.

DueTimer и LiquidCrystal включаются, но при попытке напечатать на экране сообщение - программа зависает.

 Если запускать функции пораздельности все работает. Вместе - нет.

Пример http://arduino.ru/forum/programmirovanie/zalipaet-rtt-vnutri-obrabotchik... тоже не работает. Таймер тикает, обработчик вызывается единожды.

Кто знает - разжуйте пример, пожалуйста!

Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

А в чем конфликт заключается? Может просто пины переназначить?

saer
Offline
Зарегистрирован: 12.05.2014

применяю такой шилд http://www.dfrobot.com/wiki/index.php?title=Arduino_LCD_KeyPad_Shield_%28SKU:_DFR0009%29 

пины не переназначить))

работают таймер и шилд. 

Ошибка вот в чем: цикл loop крутится, прерыванию по таймеру обрабатываются. Но если попытаться вывести lcd.print("Hello") ; то программа останавливается, луп и прерывания не крутятся. 

При этом , если в программе закоментировать все, что связано с таймером - lcd.print () работает верно

Есть подозрение, что обе библиотеки пользуются одинаковыми прерываниями/таймерами, что и приводит к конфликту. 

хочу вместу ДуеТаймер запустить RTT таймер. Описания , как сделать - нет нигде...

saer
Offline
Зарегистрирован: 12.05.2014

разобрался сам.

Таймер в DUE

// These are the clock frequencies available to the timers /2,/8,/32,/128
// 84Mhz/2 = 42.000 MHz
// 84Mhz/8 = 10.500 MHz
// 84Mhz/32 = 2.625 MHz
// 84Mhz/128 = 656.250 KHz
//
// 42Mhz/44.1Khz = 952.38
// 10.5Mhz/44.1Khz = 238.09 
// 2.625Hmz/44.1Khz = 59.5
// 656Khz/44.1Khz = 14.88 // 131200 / 656000 = .2 (.2 seconds)

// 84Mhz/44.1Khz = 1904 instructions per tick
const int led_pin = 13;
int state = false;
int interruptCtr = 1;
int S = 0;

void setup()
{
  pinMode(led_pin, OUTPUT);
  /* turn on the timer clock in the power management controller */
  pmc_set_writeprotect(false);		 // disable write protection for pmc registers
  pmc_enable_periph_clk(ID_TC7);	 // enable peripheral clock TC7

  /* we want wavesel 01 with RC */
  TC_Configure(/* clock */TC2,/* channel */1, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4); 
  TC_SetRC(TC2, 1, 131200);
  TC_Start(TC2, 1);

  // enable timer interrupts on the timer
  TC2->TC_CHANNEL[1].TC_IER=TC_IER_CPCS;   // IER = interrupt enable register
  TC2->TC_CHANNEL[1].TC_IDR=~TC_IER_CPCS;  // IDR = interrupt disable register

  /* Enable the interrupt in the nested vector interrupt controller */
  /* TC4_IRQn where 4 is the timer number * timer channels (3) + the channel number (=(1*3)+1) for timer1 channel1 */
  NVIC_EnableIRQ(TC7_IRQn);
}

void loop()
{
  // do nothing timer interrupts will handle the blinking;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// INTERRUPT HANDLERS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TC7_Handler()
{
  // We need to get the status to clear it and allow the interrupt to fire again
  TC_GetStatus(TC2, 1);
  state = !state;
  digitalWrite(led_pin, state);

  if( interruptCtr++ >= 6 )
    {
     interruptCtr = 1;
     S = !S; // are we flashing S or O
     if( S ) // set time till next interrupt
        TC_SetRC(TC2, 1, 131200); // 131200 / 656000 = .2 seconds
     else
        TC_SetRC(TC2, 1, 656000); // 656000/ 656000 = 1 second
    }
}

 

cerceli
Offline
Зарегистрирован: 19.08.2016

Не могли бы вы объяснить строки

 

07 // 42Mhz/44.1Khz = 952.38
08 // 10.5Mhz/44.1Khz = 238.09
09 // 2.625Hmz/44.1Khz = 59.5
10

// 656Khz/44.1Khz = 14.88 // 131200 / 656000 = .2 (.2 seconds

Откуда вы берете 44.1 kHz,при желании можете подсказать как настроить таймер на частоту 10kHz  спасибо)

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

cerceli, предыдущий оратор просто  взял готовый пример с ардуино.сс    Лично меня тошнит от этих CMSIS'овских функций, предпочитаю прямую запись в порты.  Вот вам прерывания 10 тыщ раз в секунду. В дефайне "freq" можно задать другую частоту в разумных пределах :)

#define freq 10000 // частота прерываний, Герц
void setup() {
pinMode (13,OUTPUT);
REG_PMC_PCER0|=1<<27; //включить тактирование "TC0" 
REG_TC0_CMR0=1<<14;//CTC mode
REG_TC0_RC0= 21E6/freq; // рассчёт частоты
REG_TC0_CCR0=5; //Обнулить счётчик и запустить.
REG_TC0_IER0=1<<4; // прерывание
NVIC_EnableIRQ(TC0_IRQn);
}

void loop() {}

void TC0_Handler(void){
 if (REG_TC0_SR0&(1<<4)==0) {return;}
REG_PIOB_ODSR^=1<<27; //дрыгать 13 ногой (как пример)
  
}
  


 

cerceli
Offline
Зарегистрирован: 19.08.2016

Согласен с Вашим мнением.Спасибо!)

cerceli
Offline
Зарегистрирован: 19.08.2016

dimax пишет:

cerceli, предыдущий оратор просто  взял готовый пример с ардуино.сс    Лично меня тошнит от этих CMSIS'овских функций, предпочитаю прямую запись в порты.  Вот вам прерывания 10 тыщ раз в секунду. В дефайне "freq" можно задать другую частоту в разумных пределах :)

#define freq 10000 // частота прерываний, Герц
void setup() {
pinMode (13,OUTPUT);
REG_PMC_PCER0|=1<<27; //включить тактирование "TC0" 
REG_TC0_CMR0=1<<14;//CTC mode
REG_TC0_RC0= 21E6/freq; // рассчёт частоты
REG_TC0_CCR0=5; //Обнулить счётчик и запустить.
REG_TC0_IER0=1<<4; // прерывание
NVIC_EnableIRQ(TC0_IRQn);
}

void loop() {}

void TC0_Handler(void){
 if (REG_TC0_SR0&(1<<4)==0) {return;}
REG_PIOB_ODSR^=1<<27; //дрыгать 13 ногой (как пример)
  
}
  


 

Добрый день, продолжаю плутать  в даташите) 

В указанном вами примере в регистре REG_TC0_CMR0 вы установили бит "CTC mode", соответственно бит TCCLKS: выбор синхронизации при этом нулевой - TIMER_CLOCK1=MCK/2=84/2=42Mhz. Период тактового сигнала =1/42000000=0.0238мкс, при таком периоде для формирования интервала в 100 мкс  необходимо 100/0.0238=4201 такт, т.е значение регистра TC0_RC0 должно быть равным 4200. Не ясен Ваш расчет частоты REG_TC0_RC0= 21E6/freq - то бишь 2100 , не могли бы Вы пояснить

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

cerceli, для формирования одного полного периода сигнала на выходе таймера требуется два такта таймера. Я просто не стал писать 42E6/2/freq, а сразу разделил :)

cerceli
Offline
Зарегистрирован: 19.08.2016

Спасибо,начал понимать чуть чуть как все работает. Голова конечно пухнет, но оно того стоит) 

 

cerceli
Offline
Зарегистрирован: 19.08.2016

Добрый день, извините за назойливость, но спросить больше некого(.Планирую запускать АЦП каждые 100мкс  через выход TIOA канала 0 таймера-счетчика, соответственно ADC_MR=1038FF83. Как я понял преобразования АЦП запускаются передним фронтом TIOA, для этого настроил  TC0 на режим WAVE=1; WAVSEL=10->REG_TC0_CMR0|=0xC000;

Не моглибы вы подсказать как можно отследить период TIOA или периодичность старта АЦП? Код работает, но не дает покоя мысль о том, что периодичность 100 мкс не соблюдается.

Serial.begin(9600);   
REG_PMC_PCER0|=1<<27; 
REG_TC0_CMR0|=0xC000;
REG_TC0_RA0=99;
REG_TC0_RC0= 3999; 
REG_TC0_CCR0=5; 

 pmc_enable_periph_clk(ID_ADC);   
 ADC->ADC_CR |=1; 
 ADC->ADC_MR= 0x1038ff00;  
ADC->ADC_CHER=0x80;     
ADC->ADC_MR |=0x10000000;
ADC->ADC_MR |=0x83; 
 

}
void loop() {
  int Uism_U=ADC->ADC_CDR[7];
  Serial.println(Uism_U);
  }

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Что у вас за перекладывания туда сюда в 10, 12 и 13 строке? Запишите один раз и лучше побитно (для удобства чтения) что вы туда кладёте. Если не ошибся в счёте, то ваш итоговый mod-регистр  такой: REG_ADC_MR = B10000001110001111111110000011  про 7ой бит сказано -Free Run Mode: Never wait for any trigger. Значит по идее АЦПшка строчит со всей своей дури. Проверить можно например прикрутив прерывание на конец конверсии (REG_ADC_IER), и дёргая там какой-нибудь порт, и частотомером узнать реальную скорость. С АЦП я не проводил экспериментов, так что советы чисто теоритические.

 

cerceli
Offline
Зарегистрирован: 19.08.2016
void setup() {
pinMode (13,OUTPUT);
pmc_enable_periph_clk(ID_ADC);  
 ADC->ADC_CR |=1; 
 ADC->ADC_MR= 0x1038ff03;  //TRGEN=1;TRGSEL=ADC_TRIG1(TIOA Output of the Timer Counter Channel 0)
ADC->ADC_CHDR=0xFFFFFFFF;   
ADC->ADC_CHER=0x80; 
ADC->ADC_IDR=~((1<<7));
REG_ADC_IER=1<<7; 
NVIC_EnableIRQ(ADC_IRQn);
// 
Serial.begin(250000);  
REG_PMC_PCER0|=1<<27;
REG_TC0_CMR0|=0x9A000;
REG_TC0_RA0=100;
REG_TC0_RC0= 4000;
REG_TC0_CCR0=5; 
}
void loop() {
  } 
  
void ADC_Handler(void){
  if (ADC->ADC_ISR&(1<<7)==0) {return;}
   REG_PIOB_ODSR^=1<<27; 
 }

//Поставил режим wave и выставил RA, RC как только не игрался с ними частота 1.2 мгц (трещания порта). Не соответствует задуманному(

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

cerceli, правильно. У вас косяк на косяке сидит. Не хотелось всё по битам проверять, но придётся. Начнём с таймера. 14 строка. TIOA -это порт таймера, даже вне зависимости примаплена ли к нему физическая нога его можно сделать как вход , как выход, и можно настроить  его поведение при разных ситуациях. В ваших настройках вообще нет ничего, что регулирует поведение TIOA, далее 13-ым битом (WAVSEL=1) вы заставляете крутить таймер счётчик по кругу,  но при этом  ни RC ни RA вообще никак не задействованы. Я конечно могу написать как нужно расставить биты, но лучше бы вам самому до этого дойти, у вас явно потенциал для этого есть. Подсказка -регистр RA не потребуется, нужно переделать wavsel, что-б счёт был до RC, а TIOA настроить так, что б он туглился при совпадении RC. С АЦП я слабо знаком, поэтому всё теоритически.  5 строка -возможно ок. 6 строка -думаю не требуется. 7- ок, 8 строка -бессмысленная операция. 9 строка -наверное ок.  23 строка - не факт...  Отступление: - в прерываниях ARM есть одно существенное отличие от прерываний AVR. Там если прога вошла в прерывание, то флаг прерывания в системном регистре прерываний автоматом снимается. А тут -не снимается. Тут нужно либо специально его как-то снять (я пока не пробовал этот путь), либо выполнить некое действие, снимающее этот флаг. Иначе выйдя из прерывания программа тотчас в него вернётся по флагу (что у вас видимо и происходит, раз с такой частотой строчит). В таймере это некое действие -прочесть регистр статуса. Вы похоже сделали для ацп по-аналогии, что в общем то логично.  Но должно ли это работать для АЦП -не факт. Возможно  нужно прочесть данные - либо ADC_CDR либо ADC_LCDR. Думаю разберётесь самостоятельно :)

 

cerceli
Offline
Зарегистрирован: 19.08.2016

Программа висела в прерывании, ситуация поменялась с добавлением строки чтения регистра данных ADC_CDR . В даташите сказано, что в режиме Waveform TIOA всегда сконфигурирован как выход, и TIOB является выходом, если он не выбран как внешний триггер. Настроил TCCLKS=TIMER_CLOCK1,  WAVE=1, счёт до RC WAVSEL =10, ACPC=11(toggle) соответственно TC_CMR0= СС000. Меняя значение TC0_RC0 получил максимальную частоту 3,7кГц при RC0=100 , меньше сколько угодно, но больше почему то не выжимает, странно если учесть что он тактирует от TIMER_CLOCK1. Не могу понять с чем это связано.


void setup() {
pinMode (13,OUTPUT);
pmc_enable_periph_clk(ID_ADC);  
 ADC->ADC_CR |=1; 
ADC->ADC_MR= 0x1038ff03;  
ADC->ADC_CHER=0x80; 
REG_ADC_IER=1<<7; 
NVIC_EnableIRQ(ADC_IRQn);
// 
Serial.begin(250000);  
REG_PMC_PCER0|=1<<27;
REG_TC0_CMR0|=0xCC000;
REG_TC0_RC0= 100;
REG_TC0_CCR0=5; 
}
void loop() {
  } 
  
void ADC_Handler(void){
int  Uism_U=ADC->ADC_CDR[7];
REG_PIOB_ODSR^=1<<27; 
}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

cerceli, таймер перестаёт оказывать влияние если АЦП не успевает. А АЦП вы как я понимаю максимально замедлили -стоят все биты PRESCAL в регистре ADC_MR

cerceli
Offline
Зарегистрирован: 19.08.2016

Все работает) Спасибо. Не моглибы Вы посоветовать литературу начинающему для понимания всех железных процессов? 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

cerceli, по DUE не встречал литературы, но можно что-то полезное найти по STM32, а они схожи. Я сам просто читаю даташит, и если что непонятно -гуглю :)

Slavapavlovsk
Offline
Зарегистрирован: 10.03.2014

dimax пишет:

cerceli, предыдущий оратор просто  взял готовый пример с ардуино.сс    Лично меня тошнит от этих CMSIS'овских функций, предпочитаю прямую запись в порты.  Вот вам прерывания 10 тыщ раз в секунду. В дефайне "freq" можно задать другую частоту в разумных пределах :)

#define freq 10000 // частота прерываний, Герц
void setup() {
pinMode (13,OUTPUT);
REG_PMC_PCER0|=1<<27; //включить тактирование "TC0" 
REG_TC0_CMR0=1<<14;//CTC mode
REG_TC0_RC0= 21E6/freq; // рассчёт частоты
REG_TC0_CCR0=5; //Обнулить счётчик и запустить.
REG_TC0_IER0=1<<4; // прерывание
NVIC_EnableIRQ(TC0_IRQn);
}

void loop() {}

void TC0_Handler(void){
 if (REG_TC0_SR0&(1<<4)==0) {return;}
REG_PIOB_ODSR^=1<<27; //дрыгать 13 ногой (как пример)
  
}
  


 

REG_PMC_PCER0|=1<<27; //включить тактирование "TC0" 
Ни как не могу понять почему именно 27???
Она как то связана с этим?
REG_PIOB_ODSR^=1<<27; //дрыгать 13 ногой (как пример)

и почему 27 дергает 13 ногу))/

эхх целый час разбираю 

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Slavapavlovsk, в данном скетче я не использовал ардуиновские функции pinMode/digitalWrite, а писал в порты напрямую. Если вы посмотрите на пинмаппинг Due, то увидите что 13 пин -это порт B27

Slavapavlovsk
Offline
Зарегистрирован: 10.03.2014
REG_PMC_PCER0|=1<<27; //включить тактирование "TC0" 

 

А она свазана с портом?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Slavapavlovsk, ну из комментария же понятно, то это запуск таймера0

Slavapavlovsk
Offline
Зарегистрирован: 10.03.2014

Так это просто совпадение?
Значить чтобы подрынкать 12 ногой мне достаточно сменить 

REG_PIOB_ODSR^=1<<27

на 

REG_PIOD_ODSR^=1<<8

mag155
Offline
Зарегистрирован: 21.12.2017

Такой вопрос можно ли в DUE сменить частоту шим по принцыпу изменения пределителя таймера ?

b707
Offline
Зарегистрирован: 26.05.2017

mag155 пишет:

Такой вопрос можно ли в DUE сменить частоту шим по принцыпу изменения пределителя таймера ?

да

mag155
Offline
Зарегистрирован: 21.12.2017

Ссылку дадите где почитать об этом? А то толком ничего не нашел.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

mag155 пишет:
Ссылку дадите где почитать об этом? А то толком ничего не нашел.

http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Corte...

mag155
Offline
Зарегистрирован: 21.12.2017

Благодарю.! Еще вопрос читал что у нее три трех канальных таймера это как ? Это ж не 9 независимых канала ?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Это смотря что понимать под словом "независимых". Вы лучше скажите, что в итоге хотите получить.

mag155
Offline
Зарегистрирован: 21.12.2017

Решил сделать частотник . Все форумы конечно ведут к stm32 но там Keil . И чё то мне думается что DUE вполне справится с этой задачей. По сути нужно 6 отдельных каналов шим. Или все же на stm32 смотреть ?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

А какие проблемы? 6 каналов ШИМ и на обычной ардуине получить можно. А stm32 и из ардуиновской среды можно программировать.

b707
Offline
Зарегистрирован: 26.05.2017

mag155 пишет:
Решил сделать частотник . Все форумы конечно ведут к stm32 но там Keil . И чё то мне думается что DUE вполне справится с этой задачей. По сути нужно 6 отдельных каналов шим. Или все же на stm32 смотреть ?

Удобнее не "6 отдельных каналов" , а 3 пары комплиментарных. Такие есть и на СТМ8 и на СТМ32, и на Атмеге2560... Да много на каких МК есть. Наверно и на Дуе..

mag155
Offline
Зарегистрирован: 21.12.2017

Вообще все упирается как я понял DEDTIME . А у stm32 он есть. Но можно в принципе его и аппаратно реализовать. Что скажите?

mag155
Offline
Зарегистрирован: 21.12.2017

Или программно флаг какой нибуть подумать ждать опускать???

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

mag155 пишет:
Вообще все упирается как я понял DEDTIME . А у stm32 он есть. Но можно в принципе его и аппаратно реализовать. Что скажите?

В DUE он УЖЕ аппаратно реализован :) В PWM-контроллере всё есть, -8 пар выходов, дид-таймы, входы защиты, и прочие полезные фичи.  Но я бы вам не советовал делать на Due, лучше найти готовый проект на стм32 и повторить его, т.к. разбираться с полного ноля во внутренней кухне таймеров Due очень трудно, а для большинства так и просто невозможно ввиду ряда причин -отсутствия нормальных обучающих материалов, примеров, итд.

mag155
Offline
Зарегистрирован: 21.12.2017

Что в место KEILA посоветуете ?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

mag155 пишет:
Что в место KEILA посоветуете ?

Ну, если мила среда Ардуино то - https://habr.com/post/395577/

А так там всего много, выбирай-не хочу. https://www.st.com/en/development-tools/stm32-ides.html

 

mag155
Offline
Зарегистрирован: 21.12.2017

Ардуино конечно ближе но как я понял например stm32 дискавери на ней не прошить ? 

mag155
Offline
Зарегистрирован: 21.12.2017

Может лучше 

Visual Studio ?

b707
Offline
Зарегистрирован: 26.05.2017

mag155 пишет:

Ардуино конечно ближе но как я понял например stm32 дискавери на ней не прошить ? 

В-первых, "СТМ32 Дискавери" - это не одна плата, а огромное семейство. И там есть и те. что можно шить в Ардуино-ИДЕ.

Во-вторых, нафига вам дорогая дискавери, когда с этим справится и банальная "BluePill" за 100 с небольшим рублей?

И в-третьих - помня старый опыт :) - с вашими-то способностями - на чем бы вы не делали. все равно это займет у вас года три и нифига не выйдет :) Нужен частотник - купите лучще готовый :)

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Я бы порекомендовал MBED. По идеологии похожа на Ардуино, но более продвинута. Поддердживается куча ARM-CortexM  процессоров включая почти весь зоопарк от STM. Из минусов (для Ардуинщиков) поддерживаются только ARMы и библиотеки от Ардуино не подходят никак. Но есть достаточно большой набор MBed-овских библиотек.

Для начала можно почитать здесь

https://habr.com/ru/post/420435/
https://habr.com/ru/company/efo/blog/308440/

mag155
Offline
Зарегистрирован: 21.12.2017

Благодарю! Попробую .

mag155
Offline
Зарегистрирован: 21.12.2017

пока остановился на arduino находил видео на буржуйском сайте где можно настраивать частоту шим,  дискретность но он использует другой синтаксис. Где об этом можно почитать ?