Генератор с регулируемой частотой на Arduino Due.

Ardudue
Offline
Зарегистрирован: 31.08.2016

Собрал генератор с регулируемой частотой  на Arduino Due по этому проекту

https://www.arduino.cc/en/Tutorial/DueSimpleWaveformGenerator

На выходе 170 Hz - для контроллера с генератором тактовой частоты 84 МГц как то бледно выглядит.

Как поднять частоту и получить прямоугольный сигнал с регулировкой частоты и скважности на выходе хотя бы в пределах от 0 до 2 MHz? 

 

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Вот есть тема, там все про это написано. Лучше б Вы по ней собирали. Не патриот Вы нашего форума :)))

Ardudue
Offline
Зарегистрирован: 31.08.2016

ЕвгенийП пишет:

Вот есть тема, там все про это написано. Лучше б Вы по ней собирали. Не патриот Вы нашего форума :)))

Так там проект не для DUE. На атмеге 328 генератор никакой. Прыжки по 266.67КГц. 

DUE со своими то 84МГц должна шагать помельче.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ну, так, адаптируйте его для due. Все основные идеи там отлично изложены. В чём проблема-то?

Jeka_M
Jeka_M аватар
Онлайн
Зарегистрирован: 06.07.2014

Ardudue, всё это делается на аппаратных таймерах. Если не найдёте готового проекта для DUE - придётся Вам изучить аппаратные таймеры микроконтроллера SAM3X8E. Зато сможете сделать свой собственный генератор с блекджеком и шл...

Ardudue
Offline
Зарегистрирован: 31.08.2016

DUE только что прикупил. Пока еще смотрю чем отличается код. До этого пользую промини на атмеге 328.

Тут и библиотеки -то не подходят -дисплей 5110 уже не подключить.

Ardudue
Offline
Зарегистрирован: 31.08.2016

Jeka_M пишет:

Ardudue, всё это делается на аппаратных таймерах. Если не найдёте готового проекта для DUE - придётся Вам изучить аппаратные таймеры микроконтроллера SAM3X8E. Зато сможете сделать свой собственный генератор с блекджеком и шл...

да вот пока кроме как этот https://www.arduino.cc/en/Tutorial/DueSimpleWaveformGenerator ничего нагуглить не удалось и удивительно, что никто не делал генератор на DUE. Ведь наверняка неплохой с двумя каналами даже для домашней лаборатории можно сделать.

Jeka_M
Jeka_M аватар
Онлайн
Зарегистрирован: 06.07.2014

Ardudue пишет:

Тут и библиотеки -то не подходят -дисплей 5110 уже не подключить.

Конечно не подходят, если там низкоуровневая работа с микроконтроллером. В отличие от других ардуин с  8-битным МК AVR, Arduino DUE - 32-битный МК ARM Cortex-M3.

Ardudue
Offline
Зарегистрирован: 31.08.2016

Jeka_M пишет:

Ardudue пишет:

Тут и библиотеки -то не подходят -дисплей 5110 уже не подключить.

Конечно не подходят, если там низкоуровневая работа с микроконтроллером. В отличие от других ардуин с  8-битным МК AVR, Arduino DUE - 32-битный МК ARM Cortex-M3.

спасибо, с этим я уже разобрался. Библиотеку для 5110 нашел. Пробую запустить тест.

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Тема интересная. Я тоже как то смотрел на дуе что бы сделать нормальный ген . Я так понял, что надо писать на С++ иначе не заставить дуе выдавать прямоугольник на мегагерцовых частотах. Я так понял на русскоязычных сайтах такие дорогие ардуины почти никто не юзает . Нищета наша не позволяет. Вот и нет проектов.

Посмотри вот здесь, чувак гонял на мегагерцах http://www.kerrywong.com/2014/09/21/on-arduino-due-pwm-frequency

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

ЕвгенийП пишет:

Ну, так, адаптируйте его для due. Все основные идеи там отлично изложены. В чём проблема-то?

Да Евгений в чем проблема-то, Вы же владелец дуе подсобили бы челу.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ivan_Kornege пишет:

 Да Евгений в чем проблема-то, Вы же владелец дуе подсобили бы челу.

Да, не вопрос, пусть выкладывает свой скетч, посмотрим, подсобим. Пока же я вижу только запрос для "Ищу исполнителя". А я в том разделе не тусуюсь. Вернее, иногда читаю и обсуждаю, но коммерческих предложений никому ещё не делал.

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

ЕвгенийП пишет:

Ivan_Kornege пишет:

 Да Евгений в чем проблема-то, Вы же владелец дуе подсобили бы челу.

Да, не вопрос, пусть выкладывает свой скетч, посмотрим, подсобим. Пока же я вижу только запрос для "Ищу исполнителя". А я в том разделе не тусуюсь. Вернее, иногда читаю и обсуждаю, но коммерческих предложений никому ещё не делал.

так он же в первом посте дал ссылку на проект, (я глянул там скетч есть,) и написал "...Как поднять частоту и получить прямоугольный сигнал с регулировкой частоты и скважности на выходе хотя бы в пределах от 0 до 2 MHz?"

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Ivan_Kornege пишет:

так он же в первом посте дал ссылку на проект, (я глянул там скетч есть,) 

Вы читать умеете? Я же ясно написал: "пусть выкладывает свой скетч". А если у него есть только ссылка на буржуйский проект, пусть идёт в "ищу исполнителя" и пишет: "хачу как тама!". Я готов помогать начинающему коллеге, который бьётся над задачей и у него не получается. А помогать всем, кому чего-то хочется - у меня помогалка не такая большая. Если у Вас достаточная, так помогите человеку - зачтётся Вам.

Ardudue
Offline
Зарегистрирован: 31.08.2016

Господа да не ссоритесь вы. В моем случае это увлечение, да и Arduino задумывался как открытый проект.

И форум что бы обмениваться информацией и что-то получалось ну для души и другим пригодилось, может быть.

Я полагал, что темы такой нет, и она разовьется для созидания, но не для ссоры.

Mining
Offline
Зарегистрирован: 31.01.2016

ОГО, какие страсти-мордасти.

Женя, а чем Вам не нравится, как Вы выразились "буржуйский проект" может Вам DUE выкинуть она-то тоже буржуйская. Ардуино действительно открытый проект для увлеченных. Это только здесь превращают его в бизнес и придумали -"ищу исполнителя".

Я так понял здесь самые увлеченные bodriy2014 и dimax. За что им низкий поклон от старика.

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

Ardudue, тема не разовьётся, ибо никому кроме вас это не интересно. По очень простой причине -тот генератор на меге328 полностью занимает свою нишу ("из говна и палок"), DUE не принесёт существенных изменений,  -шаг будет чуть мельче, -да, максимальная частота повыше, но старые проблемы останутся. - в due всё тот-же 16-битный таймер, и так-же неприемлимо на нём будет возрастать шаг перестройки частоты и скважности. Следующий технически более совершенный уровень генераторов  -это готовый чип DDS-синтезатора.

ЕвгенийП
ЕвгенийП аватар
Онлайн
Зарегистрирован: 25.05.2015

Mining пишет:

Ардуино действительно открытый проект для увлеченных. 

Увлеченные делают сами и приходят на форум с непонятками и шишками. Увлечённые сами откажутся, если им предложат сделать за них, т.к. в этом нет никакого кайфа. Если Вам это непонятно, значит мы по-разному понимаем слово "увлечённость".

Eismeer
Eismeer аватар
Offline
Зарегистрирован: 21.08.2015

Вот код, которым я формировал PPM сингнал на Due при помощи прерываний. В данном примере сформирован пакет состоящий из 9 периодов, первые 8 периодов - "0" 0.3мс, "1" 0.7-1.7мс; последний период - "0" 0.3мс, "1" 6.5-14.5мс - чтобы получить общую длину пакета 22,5мс. Если вы разобрались с прерываниями на avr, то и с этим кодом разберетесь.

#include <DueFlashStorage.h>;
DueFlashStorage dueFlashStorage;

uint32_t periods[]={42000,42000,42000,42000,42000,42000,42000,42000,42000}; // timer is clocked at 42MHz, so 42 ticks per us
uint32_t num_periods=8+1;      // number of channels +1

int ppm_channels[8];
long Frame;
long Sum;
const int InvertPPM = 0; 

void TC0_Handler()
{
   long dummy=REG_TC0_SR0;    // vital - reading this clears some flag
                              // otherwise you get infinite interrupts
   static int i=0;
   REG_TC0_RC0=periods[i++];
   if (i>=num_periods)i=0;
}

void setup(){
 pinMode(2,OUTPUT);           // port B pin 25  
 analogWrite(2,255);          // sets up some other registers I haven't worked out yet
 REG_PIOB_PDR  = 1<<25;       // disable PIO, enable peripheral
 REG_PIOB_ABSR = 1<<25;       // select peripheral B
 REG_TC0_WPMR  = 0x54494D00;  // enable write to registers
 REG_TC0_CMR0  = 0b00000000000010011100010000000000; // set channel mode register (see datasheet)
 if (InvertPPM == 1) REG_TC0_CMR0  = 0b00000000000001101100010000000000; // alternative CMR for inverted output
 REG_TC0_RC0   = 100000000;   // counter period
 REG_TC0_CCR0  = 0b101;       // start counter
 REG_TC0_IER0  = 0b00010000;  // enable interrupt on counter = rc
 REG_TC0_IDR0  = 0b11101111;  // disable other interrupts
 REG_TC0_RA0   = 12600; // Pulse lenght    0.3*1000*42=0.3ms
 Frame         = 945000; // ppm frame lenght 22.5*1000*42=22.5ms  
 NVIC_EnableIRQ(TC0_IRQn);    // enable TC0 interrupts
}

void loop(){
// 1. PPM channels
 ppm_channels[0]= analogRead(A0);          // channel 1 from 0 to 1023
 ppm_channels[1]= analogRead(A1);          // channel 2 from 0 to 1023
 ppm_channels[2]= analogRead(A2);          // channel 3 from 0 to 1023
 ppm_channels[3]= analogRead(A3);          // channel 4 from 0 to 1023
 ppm_channels[4]= analogRead(A4);          // channel 5 from 0 to 1023
 ppm_channels[5]= analogRead(A5);          // channel 6 from 0 to 1023
 ppm_channels[6]= analogRead(A6);          // channel 7 from 0 to 1023
 ppm_channels[7]= analogRead(A7);          // channel 8 from 0 to 1023

 
 // 2. Calculate the 8 channels
 Sum = 0;
 for (int i = 0; i < 8; i++)  {
   periods[i] = map(ppm_channels[i], 0, 1023, 42000, 84000);
   Sum = Sum + periods[i]; 
 }
 // 3. Calculate the sync frame
 periods[8] = Frame - Sum;
}

 

MagicianT
Offline
Зарегистрирован: 03.10.2015

Приведённый в первом посте код только с толку сбивает, он для генерации синуса. Для прямоугольных импульсов никакой Arbitrary Waveform или DDS не нужен. Вариантов 3:

1. Таймер, на дуе они 32-битные, скачки по частоте будут, там деление 42МГц / N,  т.е. 42/21 -2; 42/22 - 1.909090909;  и т.д. 

2. ШИМ (PWM), лучше, там делится 84/N,  т.е. 84/42 -2; 84/43 - 1.953488372;  и т.д.

Примеры здесь: http://www.jaxcoder.com/Article/SinglePost?postID=1976469335

 гугл, кстати, и переводить умеет, если что.

3. Внешний ФАПЧ, Si5351 например, можно модуль найти, там точность до сотых герца и почти 300 МГц (проверено) верхняя граница.

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

ЕвгенийП пишет:

Ivan_Kornege пишет:

так он же в первом посте дал ссылку на проект, (я глянул там скетч есть,) 

Вы читать умеете? Я же ясно написал: "пусть выкладывает свой скетч". А если у него есть только ссылка на буржуйский проект, пусть идёт в "ищу исполнителя" и пишет: "хачу как тама!". Я готов помогать начинающему коллеге, который бьётся над задачей и у него не получается. А помогать всем, кому чего-то хочется - у меня помогалка не такая большая. Если у Вас достаточная, так помогите человеку - зачтётся Вам.

Ну ты Паша выдал. Буржуйский проект это ваще разрыв шаблонов. Знаешь вот русскими буквами нифига не копилирует буржуйская прога. А русской проги нет нихрена. Да ты ваще этим буржуям устроиЙ байкот = выкинь все какие есть девайсы, гаджеты, писишку, ардуину и забудь этот буржуйский язык на котором програмируещ )))

Про помогалку. Нет у меня дуи =отлаживать не начем. Я же писал нищита. В гАндурасе жижа упала в цене бабло тютю . Вот бульба вырасла мож реализацию сделаю не в убыток так мож чего у китайцев и прикуплю.

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

MagicianT пишет:

Приведённый в первом посте код только с толку сбивает, он для генерации синуса. Для прямоугольных импульсов никакой Arbitrary Waveform или DDS не нужен. Вариантов 3:

1. Таймер, на дуе они 32-битные, скачки по частоте будут, там деление 42МГц / N,  т.е. 42/21 -2; 42/22 - 1.909090909;  и т.д. 

2. ШИМ (PWM), лучше, там делится 84/N,  т.е. 84/42 -2; 84/43 - 1.953488372;  и т.д.

Примеры здесь: http://www.jaxcoder.com/Article/SinglePost?postID=1976469335

 гугл, кстати, и переводить умеет, если что.

3. Внешний ФАПЧ, Si5351 например, можно модуль найти, там точность до сотых герца и почти 300 МГц (проверено) верхняя граница.

MagicianT =Красавчик дал пищу для мозгового штурма. На зиму сделал закладку бум курить чего люд наработал. Спасибо!

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016
Mining
Offline
Зарегистрирован: 31.01.2016

Реально получить и 84МГц на DUE.

У меня больше похож сигнал на синус. Щуп видимо .

uint32_t pwmPin = 8;
uint32_t maxDutyCount = 2;
uint32_t clkAFreq = 42000000ul;
uint32_t pwmFreq = 42000000ul; 
void setup() {
  pmc_enable_periph_clk(PWM_INTERFACE_ID);
  PWMC_ConfigureClocks(clkAFreq, 0, VARIANT_MCK);
  PIO_Configure(
    g_APinDescription[pwmPin].pPort,
    g_APinDescription[pwmPin].ulPinType,
    g_APinDescription[pwmPin].ulPin,
    g_APinDescription[pwmPin].ulPinConfiguration);
  uint32_t channel = g_APinDescription[pwmPin].ulPWMChannel;
  PWMC_ConfigureChannel(PWM_INTERFACE, channel , pwmFreq, 0, 0);
  PWMC_SetPeriod(PWM_INTERFACE, channel, maxDutyCount);
  PWMC_EnableChannel(PWM_INTERFACE, channel);
  PWMC_SetDutyCycle(PWM_INTERFACE, channel, 1);
  pmc_mck_set_prescaler(2);
}
void loop() 
{
}

 

MagicianT
Offline
Зарегистрирован: 03.10.2015

В 9-м посте есть линк, на страницу с картинками, так там тоже сплошной синус. 

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Вот здесь чувак выложил библиотеки для таймеров DUE

https://github.com/ivanseidel/DueTimer

AVGN
Offline
Зарегистрирован: 10.10.2016

Ivan_Kornege пишет:

Тема интересная. Я тоже как то смотрел на дуе что бы сделать нормальный ген . Я так понял, что надо писать на С++ иначе не заставить дуе выдавать прямоугольник на мегагерцовых частотах. Я так понял на русскоязычных сайтах такие дорогие ардуины почти никто не юзает . Нищета наша не позволяет. Вот и нет проектов.

Посмотри вот здесь, чувак гонял на мегагерцах http://www.kerrywong.com/2014/09/21/on-arduino-due-pwm-frequency

Поддерживаю. Конечно, due дороговата, но генератор прямоугольных импульсов с прилично регулируемой скважностью хотя бы с шагом 0,1% действительно был бы интересен вмастерской радиолюбителям.

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

AVGN, это где такой шаг скважности нужен? Сколько пользуюсь, мельче чем 1% шаг делать надобности не возникало.

AVGN
Offline
Зарегистрирован: 10.10.2016

dimax, создание и отстройка всякого рода силовых резонансных источников. Например, отстройка резонансных трансформаторов сварочного аппарата или компактного и экономичного блока питания для светодиодов.

Когда подаете импульсы различной скважности на трансформатор (в качестве сердечника ферриты) много всяких полезных эффектов присутствует.

Dissipator
Offline
Зарегистрирован: 02.12.2016

Добрый день.  Пытаюсь сделать регулируемый генератор на прерываниях и таймерах Ардуино DUE.

Если коротко то длинна импульса должна быть пропорциональна напряжению на АЦП .

АЦП сконфигурировал – все работает на очень приличной скорости.

Таймер для отсчета длинны импульса  работает отлично, но есть большое но:

Вот рабочий код , писал по памяти для примера - может чтото не учел, забыл:

uint32_t T1;
int state = false;

void setup() {
  // initialize serial communications at 9600 bps:
  analogReadResolution(12);

  REG_PIOB_PER |= 1 << 27;
  REG_PIOB_OER |= 1 << 27;

  pmc_set_writeprotect(false);       // disable write protection for pmc registers
  pmc_enable_periph_clk(ID_TC8);     // enable peripheral clock TC8
  TC_Configure(TC2, 2, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
  TC_SetRC(TC2, 2, 131200);
  TC_Start(TC2, 2);
  /* we want wavesel 01 with RC */
  TC2->TC_CHANNEL[2].TC_IER = TC_IER_CPCS; // IER = interrupt enable register
  TC2->TC_CHANNEL[2].TC_IDR = ~TC_IER_CPCS; // IDR = interrupt disable register

  NVIC_EnableIRQ(TC8_IRQn);
}
void loop() 
{  
T1=1000;
TC_SetRC(TC2, 2, T1);
}
void TC8_Handler()
{  
  // We need to get the status to clear it and allow the interrupt to fire again
  TC_GetStatus(TC2, 2);
  state = !state;
  if (state)
    REG_PIOB_SODR |= 1 << 27; // ON PB27
  else
    REG_PIOB_CODR |= 1 << 27; // OFF PB27
  {  
}

Но стоит с T1 произвести какие либо манипуляции, например T1++; if (T1>1000){T1=0;}, или математические действия, как таймер перестает работать , ну или прерывание прекращается.

Может кто знает как с этим бороться.

Спасибо.

Так же выложу фото,  на нем показано импульсом( на 13 ноге (желтый))  работу АЦП в автоматическом режиме , считываетпо прерываниям показания с 5 разных ножек.

Код так же примерный:

int data[5];
int a1=0;

void setup()
{
  
  Serial.begin(9600);
  ConfigureADC();
  ConfigureTimer();
}

void loop()
{}



void ConfigureADC(void)
{
adc_enable_channel(ADC, (adc_channel_num_t)7); //(A0) ---
 adc_enable_channel(ADC, (adc_channel_num_t)6);  //(A1) A
 adc_enable_channel(ADC, (adc_channel_num_t)5);  //(A2) B
 adc_enable_channel(ADC, (adc_channel_num_t)4);  //(A3) C
 adc_enable_channel(ADC, (adc_channel_num_t)3);  //(A4) 0-20
 adc_enable_interrupt(ADC, ADC_IER_DRDY);
 /* Enable ADC interrupt. */
 NVIC_EnableIRQ(ADC_IRQn);
}

void ConfigureTimer(void)
{
  pmc_set_writeprotect(false);       // disable write protection for pmc registers
  pmc_enable_periph_clk(ID_TC0);     // enable peripheral clock TC0
  TC_Configure(/* clock */TC0,/* channel */0, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_ACPC_Msk | TC_CMR_TCCLKS_TIMER_CLOCK4);//TC_CMR_ACPC_TOGGLE TC_CMR_ACPC_Msk TC_CMR_ACPC_SET TC_CMR_WAVSEL_UP_RC
  TC_SetRC(TC0, 0, 41);
  TC_Start(TC0, 0);
  adc_configure_trigger(ADC, ADC_TRIG_TIO_CH_0, 0);
}





// ADC Interrupt handler.
void ADC_Handler(void)
{

  if ((adc_get_status(ADC) & ADC_ISR_DRDY) == ADC_ISR_DRDY)
  {
REG_PIOB_SODR |= 1 << 27; // ON PB27

    data[a1]=REG_ADC_LCDR;
    a1++; 
REG_PIOB_CODR |= 1 << 27; // OFF PB27
  }
}

 

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

Вроде разобрался с портами на DUE, глядишь так и до таймеров доберусь)

Написал обработчик энкодера, уже что-то. Можно начинать регистры крутить )


//обработчик энкодера для ARDUINO DUE (c)Dimax
//49 -кнопка энкодера, переключает шаг 1-10-100-1000
//50,51 - выводы энкодера
volatile uint32_t enc=1000; //переменная энкодера
volatile uint16_t divider=1; //default 
volatile boolean mon_flag=0; //вывод данных
void setup() {
Serial.begin(115200);
 REG_PMC_PCER0|=1<<13; //enable "PIOC" clock
  REG_PIOC_PER|=(1<<12)|(1<<13)|(1<<14); //PIO enable
   REG_PIOC_IFER|=(1<<12)|(1<<13)|(1<<14); //glitch enable
    REG_PIOC_PUER|=(1<<12)|(1<<13)|(1<<14); //PullUP enable
    REG_PIOC_DIFSR|=(1<<12)|(1<<13)|(1<<14);//Debouncing enable
  attachInterrupt(50,encoder_func,CHANGE);
attachInterrupt(49,divider_func,FALLING);

}

void loop() {
 if(mon_flag){
   mon_flag=0;
   Serial.print("Enc=");
   Serial.print(enc);
   Serial.print("  Div=");
   Serial.println(divider);
   }
  }


void encoder_func(){
uint8_t n = (uint32_t)(REG_PIOC_PDSR & 0x3FFF) >>12;
 if (n==0||n==3){enc+=divider;}  else {enc-=divider;}
  mon_flag=1;
  }

void divider_func(){
     switch (divider){ 
        case 1: divider=10;     break;
        case 10: divider=100;    break;
        case 100: divider=1000;   break;
        case 1000: divider=1; break; 
      } mon_flag=1;
   }//end func
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Разобрался с таймером-счётчиком на Дуе  в режиме генерации частоты . Тут всё не так, как на меге328. Возможностей гораздо больше, и настраивается всё иначе. Я бы сказал почти ничего общего.   Таймер можно использовать как PWM генератор, это при том, что в МК есть специализированный  PWM-генератор, в котором функций ещё больше. Но туда соваться пока страшно :) Реально тактироваться может от 42МГц. Можно и на 84 разогнать, пробовал, но на этой частоте перестаёт работать Serial. Наверняка ещё что нибудь отвалится. Коллега MagicianT писал, то специализировагнный PWM таймер как раз может работать штатно на 84Мгц шине, но до него пока не добрался.  В качестве разминки написал римейк вот этого скетча , теперь вариант для DUE. В сериале можно запросить частоту в Герцах, программа ответ какую частоту реально сгенерила. Максимум 21000000 герц.

 

// выход генератора -пин 2 на Arduino DUE
void setup() {
Serial.begin(9600);
 REG_PIOB_OER|=1<<25; //b25 будет выход
  REG_PIOB_PDR|=1<<25;//b25 будет периферия
   REG_PIOB_ABSR|=1<<25; //периферия "Б" выбрана
    REG_PMC_PCER0|=1<<27; //включить тактирование "TC0" 
     REG_TC0_CMR0=(1<<14)|(1<<15)|(1<<18)|(1<<19);//WAVE конфиг
    }

void loop() {
static uint32_t freq2tc=0;
 if (Serial.available() > 0){
    freq2tc = Serial.parseInt();    
    REG_TC0_RC0= 21E6/freq2tc;  
   REG_TC0_CCR0=5;
    Serial.print(21E6/REG_TC0_RC0,0); 
     Serial.println(" Herz");
      } //end if serial..
}
  
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Частично разобрался с PWM Таймером DUE. Таймер тактируется по умолчанию от 84МГц, стало быть макс. частота без извращений -42Мгц. А вот разрядность ШИМ всего лишь 16 бит оказалась, а не 32 как я думал.  По основному назначению, - делать PWM, настроить как выяснилось не очень трудно, но там есть ещё  куча регистров, которые пока для меня непонятны. Надеюсь всё же разобраться со временем.

Написал аналогичный предыдущему скетч, но с регулировкой скважности. Параметры такие:  минимальная частота 2 Гц, максимальная -42МГц.  Шаг скважности -1% после частоты 840кГц шаг падает. Кол-во шагов скважности нетрудно узнать разделив 84E6 на нужную частоту. Высокие частоты генерятся с большими промежутками, тоже нетрудно  узнать деля 84E6 на целочисленные делители. ( 42МГц, 28МГц,21МГц,16.8МГц,14МГц, и.т.д.)  

Использование: -В терминалке послать цифру частоты в герцах, в ответ придёт сколько реально таймер смог сделать. В качестве опции через пробел можно указать дьюти(скважность) в процентах. Например: 1000 20. Отправка без второго числа делает скважность автоматом 50%.

//выход pwm 35 pin Arduino DUE (PC3,PWMH0)
void setup() {
Serial.begin(9600);
REG_PIOC_OER|=1<<3; //PC3 будет выход
 REG_PIOC_PDR|=1<<3;//PC3 будет периферия
  REG_PIOC_ABSR|=1<<3; //периферия "Б" выбрана    
   REG_PMC_PCER1|=1<<4; //включить тактирование "PWM"    
   REG_PWM_WPCR=0;//отлючение защиты от записи 
   REG_PWM_CLK=0; //клоки АБ выключены
   REG_PWM_CMR0=1; //Мастерклок прескалер по умолчанию /2
  REG_PWM_CPRD0= 42000u; // период по умолчанию  -1000 Герц
 REG_PWM_CDTY0=21000ul; //дьюти  по умолчанию 50%
REG_PWM_ENA|=1<<0;//Включить PWM 0 канал
}

void loop() {
uint32_t divider=1, icr=0, freq2pwm=0; uint16_t duty=0;
if(Serial.available() > 0){
  freq2pwm = Serial.parseInt();      
    duty=Serial.parseInt();
    icr=(84E6 /freq2pwm /divider);
      for(byte i=1; i<12;i++){
        if (icr >65535) { 
           divider= 1<<i;
           icr=(84E6 /freq2pwm /divider); }
        else { REG_PWM_CMR0 = i-1; break; } //делитель в регистр
     }//end for
REG_PWM_CPRDUPD0=icr; //запись периода
 if (duty){ REG_PWM_CDTYUPD0= (uint32_t)icr*(100-duty)/100; } 
  else { REG_PWM_CDTYUPD0=icr/2;}
    Serial.print("Freq= "); 
   Serial.print((uint32_t)84E6/icr/divider); Serial.println(" Herz"); 
 }// end is serial
} //end loop


 

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

Простой DDS генератор на Arduino DUE.

Изучал работу ЦАПа, попутно написал программульку. Представляет собой классический DDS -синтезатор, с 32-битным аккумулятором фазы. Таблица синуса 14-битная, автоматически рассчитывается и разворачивается в памяти, занимает 16кБ, а что жалеть то? Коли памяти вагон :) Возможный шаг изменения частоты очень маленький, специально не считал, но не хуже 0,1Герц 

Использование : В  первую строчку подставлять нужную частоту  (float/int без разницы), на выходе  DAC0 -эта частота появится. Ограничений не ставил, но после 10кГц уже потихоньку начинает падать качество. на картинке 20кГц, -ещё прилично. Но если задирать ещё выше -то синус будет совсем ступенчатый. Изменение частоты на ходу не предусмотрено, т.к. процесс съедает почти 100% ресурсов. Можно в принципе крутить энкодером, сидящем на прерывании (пост#31 например),  а в прерывании пересчитывать, но если разрешить прерывания то существенно усилится джиттер. Да и небыло собссно цели сделать какое-то законченное устройство, ибо генератор на меге328 из соседней темы вполне решает все задачи.

 

#define freq 20.000  // требуемая частота в герцах
uint32_t shag= freq * 2761.069715582566;   //  попугаев на Герц
uint16_t sine_wave[16384]; uint32_t datatemp, akkum; 
void setup(){
for(uint16_t n=0; n<16384; n++){sine_wave[n]=4095*(sin(TWO_PI*float(n)/16384)+1)/2 ;}
REG_PIOB_OER|=1<<15; //PB15 будет выход
 REG_PIOB_PDR|=1<<15;//PB15 будет периферия
   REG_PMC_PCER1|=1<<6; //включить тактирование "DACC"    
     REG_DACC_CR=1; //dacc reset;
      REG_DACC_MR=1<<21;//maxspeed
       REG_DACC_CHER=1; //channel 0 enable
      __disable_irq();
         while(1){
      datatemp= sine_wave[(akkum+=shag)>>18];
    if(REG_DACC_ISR&1==1){ REG_DACC_CDR=datatemp;}  
  }
}
void loop(){}

 

AVGN
Offline
Зарегистрирован: 10.10.2016

dimax, неплохой шаг 0.1. С таким шагом уже можно эксперементировать с трансформаторами. Но лучше генерить прямоугольник до 2МГц с шагом 0.1 и  с изменяемой скважностью с шагом 0,1%.

Я собрал Ваш генератор на атмеге328, но у него шаг перестройки грубый.

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

AVGN, что б генерить прямоугольник 2 МГц с шагом скважности  0,1% нужно таймеру работать на тактовой частоте 4 ГГц.  Генератор по цене автомобиля будет :)) А вот менять частоту с шагом 0,1Гц вполне может бюджетный синтезатор AD9850.

Mining
Offline
Зарегистрирован: 31.01.2016

dimax пишет:

Простой DDS генератор на Arduino DUE.

... Да и небыло собссно цели сделать какое-то законченное устройство, ибо генератор на меге328 из соседней темы вполне решает все задачи.

Ничего немножко требуется передышка... всегда.  Верю в Вас. Пытливый ум не даст Вам бросить то, что уже начато с DUE.

В Чайна уже сориентировались и предлагают набор по цене DUE (+дисплей+энкодер+кнопочка со скетчем многофункционального генератора с частотомером. Я не брал, по отзывам сыроват скетч - плохо работает энкодер.

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

Каждый раз проверяя какую-нибудь новую возможность поражаюсь, насколько же в АРМ контроллерах всё доведено до ума. Раньше нопример считал, что считать длительность импульса/частоту в меге 328 очень удобно через ICP-прерывание. Так  вот , в сравнении с ДУЕ это извращение! Тут всё гибче и продуманней,  тут настраиваешь таймер на захват, и никаких прерываний не нужно, просто забираешь из регистров готовые измеренные значения частоты и скважности (в тактах контроллера разумеется). А 32-битная разрядность позволяет считать частоты от 0,1 Герца вообще без прескалеров. В общем очередной примерчик, -скетч считает частоту измеряя длительность импульса, этот алгоритм не позволяет считать высокие частоты, высокая точность измерения примерно до 100кГц, средняя точность до 1МГц, выше уже слишком существенные ошибки начнутся.

void setup() {
Serial.begin(115200);
 REG_PIOB_PDR|=1<<25;//b25 будет периферия  (TIOA0, **pin2-вход ардуино дуе*** )
  REG_PIOB_ABSR|=1<<25; //периферия "Б" выбрана
   REG_PMC_PCER0|=1<<27; //включить тактирование "TC0" 
    REG_TC0_CMR0=(1<<19)|(1<<16)|(1<<10)|(1<<9);//капчур конфиг
     REG_TC0_CCR0=5; //Обнулить счётчик и запустить.
}

void loop() {
if (REG_TC0_SR0&B00110000) {
    uint32_t ra=REG_TC0_RA0; 
      uint32_t rb=REG_TC0_RB0;
        float freq= (float)42E6/rb;
          float duty= (float) (rb-ra) * 100 / rb;
          Serial.print(freq,3); 
         Serial.print(" Hz, Duty=");  
        Serial.print(duty); Serial.println(" %");  
        }
 
delay(300); // чтоб не мельчишило :)
  }



 

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

Привет! dimax

Перебираетесь на 32битные камни.

Подскажите кроме даташитов используете еще материалы, если да поделитесь пожалуйста.

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

bodriy2014, только даташит. К сожалению хороших материалов нет нигде. Гуглежом что-то полезное изредка  встречалось, например сколько я не раскуривал даташит -так и не мог понять,  как правильно кидать байты в ЦАП через ДМА. Гугл привёл толи на  gaw.ru,  то ли на микросин.ру,  где из крохотной заметки, написанной довольно убогим формальным языком наконец с трудом понял как  всё это устроено. В принципе всё искусство работы с периферией заключается в глубоком знании принципов её работы.  Очень большую роль сыграло то, что с устройством таймеров avr я основательно разобрался в своё время. Думаю без этой "базы" не за что бы не осилил ARM таймеры, т.к. примеров низкоуровнего доступа к периферии DUE нет вообще нигде, только редкие примеры на функциях из библиотеки CMSIS, которые все правят под себя, но мало кто понимает как это работает.

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

dimax пишет:

bodriy2014, только даташит. К сожалению хороших материалов нет нигде. Гуглежом что-то полезное изредка  встречалось, например сколько я не раскуривал даташит -так и не мог понять,  как правильно кидать байты в ЦАП через ДМА. Гугл привёл толи на  gaw.ru,  то ли на микросин.ру,  где из крохотной заметки, написанной довольно убогим формальным языком наконец с трудом понял как  всё это устроено. В принципе всё искусство работы с периферией заключается в глубоком знании принципов её работы.  Очень большую роль сыграло то, что с устройством таймеров avr я основательно разобрался в своё время. Думаю без этой "базы" не за что бы не осилил ARM таймеры, т.к. примеров низкоуровнего доступа к периферии DUE нет вообще нигде, только редкие примеры на функциях из библиотеки CMSIS, которые все правят под себя, но мало кто понимает как это работает.

Спасибо за то, что делитесь наработками!

Я в 32 вьезжаю туго, одно дело в регистре 8 знаков а 32  тяжело визуально запомнить.

Приходится резать тетрадь на блокноты и постоянно наброски делать.!(

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

Частотометр с другим принципом измерения - один таймер отсчитывает  секунду, другой таймер  считает количество входных импульсов пришедших на тактовый вход за эту секунду. Точность счёта -1 Герц (без учёта  неточности кварца).  Что -бы избежать необходимости прерываний пришлось пойти на применение аппаратной петли -нужно связать эти два таймера. (Ради повышения точности измерения, -получаем полностью аппаратный частотомер, не влияющий на загрузку МК).  Пин А7 нужно соединить с пином 2.  Вход ипульсов подавать на пин А5. Считает частоту от от 1-го Герца и до... даташит говорит, цитата "In all cases, if an external clock is used, the duration of each of its levels must be longer than the peripheral clock period. The external clock frequency must be at least 2.5 times lower than the peripheral clock" то есть  по идее не более, чем 16.8 МГц , но я подавал 21МГц -отображалось верно, возможно потому, что сгенерил их на этом же МК :) . В отличие от предыдущего частотомера не измеряет скважность.

/* Частотометр для ARDUINO DUE, вариант подсчёта количества импульсов за 1 секунду
 *  вход частоты -(А5), **выход тактов сброса 1Гц (А7пин) соединить с входом сброса (2пин)*** 
*/
void setup() {
Serial.begin(115200);
REG_PMC_PCER0|=(1<<27)|(1<<28); //включить тактирование TC 0 и 1 канал 
REG_PIOB_PDR|=(1<<25);//b25 будет периферия
REG_PIOB_ABSR|=(1<<25); //периферия "Б" выбрана
REG_PIOA_PDR |= (1<<2)|(1<<4); // (pinA7, TIOA1) ,( pinA5 TCLK1)будет периферия 
REG_TC0_CMR0=(1<<14)|(1<<15)|(1<<18)|(1<<19);//конфиг генератора 1Герц
REG_TC0_RC0=42E6;
REG_TC0_CMR1 = (1<<1)|(1<<2)|(1<<8)|(1<<10)|(1<<16)|(1<<17); //конфиг счётчика импульсов
REG_TC0_CCR0=5; REG_TC0_CCR1=5;  //Обнулить счётчики и запустить таймеры.


}
void loop() {

if (REG_TC0_SR1&B10100000){Serial.print(REG_TC0_RA1); Serial.println(" Hz  "); } 
}

 

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

Добил DDS-генератор из #34 до завершённого устройства.

Таблицы (синус, треугольник, пила, меандр) рассчитываются программно и забрасываются в массив  uint16_t * 16384. Энкодером регулируется частота от 1Гц до 100кГц  шагами по 1/10/100/1000 Гц. Кнопка энкодера переключает шаг, дополнительная кнопка переключает таблицы. Использовался стандартный lcd индикатор 1602 c I2C модулем сзади. Библиотека автодетектит адрес LCD, так что указывать его не нужно.

 

/* DDS Generator for Arduino DUE (c) Dimax
pin48 - кнопка, переключает wave таблицы (синус-треугольник-пила-меандр)
pin 49 -кнопка энкодера, переключает шаг 1-10-100-1000
pin 50,51 - выводы энкодера
pin DAC0 -выход сигнала
I'm use LCD1602 library:  https://github.com/duinoWitchery/hd44780
*/
 #define ddsherz 2556.540510816352
  #include <Wire.h> 
   #include <hd44780.h>
    #include <hd44780ioClass/hd44780_I2Cexp.h> 
     hd44780_I2Cexp lcd;
    volatile int32_t freq=1000; //частота в герцах по умолчанию
    volatile uint16_t enc_shag=100; //шаг по умолчанию 
  volatile boolean change=0; //флаг необходимости перезапуска DDS. 0-нужно. 1-не нужно
 volatile uint8_t mode=0;//переменная режимов (синус, треугольник, пила, меандр)
uint16_t wave[16384];  

void setup(){
lcd.begin(16,2);
  lcd.backlight();
   lcd.setCursor(0,0);
    lcd.print("DDS Generator V1.0");
     lcd.setCursor(0,1);
      lcd.print("Loading...");
       delay(1000);
        REG_PIOB_PDR|=1<<15;//PB15 будет периферия
         REG_PMC_PCER1|=1<<6; //включить тактирование "DACC"    
        REG_DACC_CR=1; //dacc reset;
       REG_DACC_MR=1<<21;//maxspeed
      REG_DACC_CHER=1; //channel 0 enable
     REG_PMC_PCER0|=1<<13; //enable "PIOC" clock
    REG_PIOC_PER|=(1<<12)|(1<<13)|(1<<14)|(1<<15); //PIO enable
  REG_PIOC_PUER|=(1<<12)|(1<<13)|(1<<14)|(1<<15); //PullUP enable
 REG_PIOC_IFER|=(1<<12)|(1<<13)|(1<<14)|(1<<15); //glitch enable
REG_PIOC_SCIFSR|=(1<<12)|(1<<13)|(1<<14)|(1<<15); //The Glitch Filter is able to filter glitches with a duration < Tmck/2
 REG_PIOC_SCDR=64;//Slow Clock Divider Selection for Debouncing
  REG_PIOC_DIFSR|=(1<<12)|(1<<13)|(1<<14)|(1<<15); ////Debouncing enable  
   attachInterrupt(50,encoder_func,CHANGE);
    attachInterrupt(49,enc_key_func,FALLING); 
     attachInterrupt(48,wave_func,FALLING);
      NVIC_DisableIRQ(UOTGHS_IRQn);// отключить IRQ USB OTG
 
}//end setup

void loop(){         
 (*(RwReg*)0xE000E010)=0x10007;
  REG_DACC_CDR=2047;
   static uint8_t old_mode=255;
    static uint32_t akkum;
    if (freq>1E5){ freq=1E5;} if (freq<0){ freq=0;}
     uint32_t dds_shag= freq * ddsherz;   //  попугаев на Герц
      lcd.clear();
       lcd.setCursor(0,0); 
        lcd.print("Freq=");
         lcd.print(freq); 
          lcd.print(" Hz"); 
           lcd.setCursor(0,1);
            lcd.print("Step="); 
            lcd.print(enc_shag); 
           switch (mode) {
          case 0:   lcd.print("  Sinus"); break;
         case 1:   lcd.print("  Triangle"); break;
        case 2:   lcd.print("  Saw"); break;
       case 3:   lcd.print("  Meandr");
      }
if (mode != old_mode){
 if( mode==0) { for(uint16_t n=0; n<16384; n++){wave[n]=4095*(sin(TWO_PI*float(n)/16384)+1)/2 ;} }
   else if( mode==1) { for(uint16_t n=0; n<16384; n++){if (n<8192){ wave[n]=(n/2);} else {wave[n]=(16383-(n/2));} }}
    else if( mode==2) { for(uint16_t n=0; n<16384; n++){wave[n]=(n/4);} }
     else if( mode==3) { for(uint16_t n=0; n<16384; n++){if (n<8192) {wave[n]=(0);} else{wave[n]=4095;} } }
    old_mode = mode;
   } //end if mode != oldmode
(*(RwReg*)0xE000E010)=0;//отключить SysTick
  change=1;  /// ******вход в цикл DDS***** //////
      while(change){
       if(REG_DACC_ISR&1==1){ 
        REG_DACC_CDR = wave[(akkum+=dds_shag)>>18];
        }//end check ready 
      } //end while
  }//end loop


void encoder_func(){
if (change==0){return;}
uint8_t n = (uint32_t)(REG_PIOC_PDSR & 0x3FFF) >>12;
  if (n==0||n==3){freq+=enc_shag;}  else {freq-=enc_shag;}
    change=0; 
     }

void enc_key_func(){
    if (change==0){return;}
     switch (enc_shag){ 
        case 1: enc_shag=10;     break;
         case 10: enc_shag=100;    break;
         case 100: enc_shag=1000;   break;
        case 1000: enc_shag=1;
      } 
change=0;
   }//end func

void wave_func() {
if (change==0){return;}
mode++; if (mode>3){ mode=0;}
 change=0;
  }
Mining
Offline
Зарегистрирован: 31.01.2016

Молодчина! Поставил +!

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

прикольненько, тут хоть понятно как перепилить под другой дисплей)

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

Mining, Xumuk   Вообще-то сам я очень скептически отношусь к полезности сего творения, т.к. его тех. характеристики не лучше, чем у аналогичного DDS модуля на резисторах из состава генератора версий 2.x По крайней мере на осцилографе выгядит всё так-же. Не смотря на 12 бит разрядность ЦАП. Вернее  преимущества есть, но только на низких частотах, менее 5 кГц.  А причина тому недостаточно быстрый ЦАП на Дуе. Если не ошибаюсь у него скорострельность ~ 1,7 мегасемпла в секунду. Т.е. что бы отрисовать ПОЛНОСТЬЮ самую простенькую wave - табличку на 256 байт получим исходящую частоту всего лишь 1700000/256 = 6640 Герц! Тут главное удобство в том, что цап встроен, и не нужно ничего паять :)

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

dimax пишет:

Mining, Xumuk   Вообще-то сам я очень скептически отношусь к полезности сего творения, т.к. его тех. характеристики не лучше, чем у аналогичного DDS модуля на резисторах из состава генератора версий 2.x По крайней мере на осцилографе выгядит всё так-же. Не смотря на 12 бит разрядность ЦАП. Вернее  преимущества есть, но только на низких частотах, менее 5 кГц.  А причина тому недостаточно быстрый ЦАП на Дуе. Если не ошибаюсь у него скорострельность ~ 1,7 мегасемпла в секунду. Т.е. что бы отрисовать ПОЛНОСТЬЮ самую простенькую wave - табличку на 256 байт получим исходящую частоту всего лишь 1700000/256 = 6640 Герц! Тут главное удобство в том, что цап встроен, и не нужно ничего паять :)

да не генератор на такой ардуинке я делать не собираюсь)))) я думаю повторить Ваш проект на обычной уно))) только под другой дисплей 1.44тфт, но пока нет времени разбитраться)

Волшебник
Offline
Зарегистрирован: 22.12.2016
dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013
 
 

Mining, Xumuk   Вообще-то сам я очень скептически отношусь к полезности сего творения, т.к. его тех. характеристики не лучше, чем у аналогичного DDS модуля на резисторах из состава генератора версий 2.x По крайней мере на осцилографе выгядит всё так-же. Не смотря на 12 бит разрядность ЦАП. Вернее  преимущества есть, но только на низких частотах, менее 5 кГц.  А причина тому недостаточно быстрый ЦАП на Дуе. Если не ошибаюсь у него скорострельность ~ 1,7 мегасемпла в секунду. Т.е. что бы отрисовать ПОЛНОСТЬЮ самую простенькую wave - табличку на 256 байт получим исходящую частоту всего лишь 1700000/256 = 6640 Герц! Тут главное удобство в том, что цап встроен, и не нужно ничего паять :)

 

 

 

Не согласен. Не надо по 256-и точкам считать, 1.7 МГц это 500 кГц синуса с нормальным фильтром по выходу. Посмотрите на АД9850, при тактовой 125 МГц, нокого не удивляет паспортное значение 40 МГц по выходу.

Я тут выкладывал ардуино ДУЕ скетч, <правильный> генератор синуса, с использованием ДМА - процессор отдыхает.

https://forum.arduino.cc/index.php?topic=224672.0


#define    NWAVE               80

uint16_t  Sinewave[2][NWAVE] = {
  {
   +4095,   +4093,   +4089,   +4081,   +4070,   +4056,   +4038,   +4018,   +3995,   +3968,   +3939,   +3907,   +3872,   +3834,   +3793,   +3750,
   +3704,   +3656,   +3605,   +3551,   +3495,   +3438,   +3377,   +3315,   +3251,   +3185,   +3118,   +3048,   +2977,   +2905,   +2831,   +2757,
   +2681,   +2604,   +2526,   +2447,   +2368,   +2289,   +2209,   +2128,   +2048,   +1968,   +1887,   +1807,   +1728,   +1649,   +1570,   +1492,
   +1415,   +1339,   +1265,   +1191,   +1119,   +1048,    +978,    +911,    +845,    +781,    +719,    +658,    +601,    +545,    +491,    +440,
    +392,    +346,    +303,    +262,    +224,    +189,    +157,    +128,    +101,     +78,     +58,     +40,     +26,     +15,      +7,      +3,
  },
  {
      +1,      +3,      +7,     +15,     +26,     +40,     +58,     +78,    +101,    +128,    +157,    +189,    +224,    +262,    +303,    +346,
    +392,    +440,    +491,    +545,    +601,    +658,    +719,    +781,    +845,    +911,    +978,   +1048,   +1119,   +1191,   +1265,   +1339,
   +1415,   +1492,   +1570,   +1649,   +1728,   +1807,   +1887,   +1968,   +2048,   +2128,   +2209,   +2289,   +2368,   +2447,   +2526,   +2604,
   +2681,   +2757,   +2831,   +2905,   +2977,   +3048,   +3118,   +3185,   +3251,   +3315,   +3377,   +3438,   +3495,   +3551,   +3605,   +3656,
   +3704,   +3750,   +3793,   +3834,   +3872,   +3907,   +3939,   +3968,   +3995,   +4018,   +4038,   +4056,   +4070,   +4081,   +4089,   +4093
  }
};

uint16_t  SineFast[2][NWAVE] = {
  {
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939
  },
  {
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939,
   +4095,   +3939,   +3495,   +2831,   +2048,   +1265,    +601,    +157,      +1,    +157,    +601,   +1265,   +2048,   +2831,   +3495,   +3939
  }
};

            int       fast_mode  =    0;
            int       freq_inhz  = 1000; // Default Hz
            int       freq_intc  =    0; 
            int       user_intf  =    0;

volatile   uint16_t   sptr       =    0;

void setup()
{
  Serial.begin (115200); 
  dac_setup();        
  freq_intc = freqToTc(freq_inhz);
  TC_setup();        
  setup_pio_TIOA0(); 
}

int tcToFreq( int tc_cntr)
{
  int freq_hz;     

  if( tc_cntr == 0 ) return 1000;
  if( fast_mode ) freq_hz = (420000000UL / tc_cntr) / (2 * NWAVE); 
  else            freq_hz = ( 42000000UL / tc_cntr) / (2 * NWAVE);
  return freq_hz;   
}

int freqToTc( int freq_hz)
{
  int tc_cntr = 0;

  if( freq_hz == 0 ) return 25;
  if( fast_mode ) tc_cntr = (420000000UL / freq_hz) / (2 * NWAVE); 
  else            tc_cntr = ( 42000000UL / freq_hz) / (2 * NWAVE);
  return tc_cntr;
}

void switch_mode( int mode)
{
  if( mode == 0 ) 
  {
    DACC->DACC_TPR  =  (uint32_t)  Sinewave[0];      // DMA buffer
    DACC->DACC_TCR  =  NWAVE;
    DACC->DACC_TNPR =  (uint32_t)  Sinewave[1];      // next DMA buffer
    DACC->DACC_TNCR =  NWAVE;
  }
  else
  {
    DACC->DACC_TPR  =  (uint32_t)  SineFast[0];      // DMA buffer
    DACC->DACC_TCR  =  NWAVE;
    DACC->DACC_TNPR =  (uint32_t)  SineFast[1];      // next DMA buffer
    DACC->DACC_TNCR =  NWAVE;
  }
}

void loop() 
{
  char in_Byte;
  int     temp;
          
  if (Serial.available() > 0) {
    in_Byte = Serial.read();
    // Message Format To Set  Frequency:  1000f + "send".
    if((in_Byte >= '0') && (in_Byte <= '9')) 
    {
      user_intf = (user_intf * 10) + (in_Byte - '0'); 
    }
    else
    { 
      if (in_Byte == 'f') // end delimiter 
      {
        if ((user_intf > 20) && (user_intf < 100000)) 
        {
          freq_inhz = user_intf;
            if( freq_inhz > 10000 ) temp = 1;
            else                    temp = 0;
            if (temp != fast_mode) 
            {
              fast_mode = temp;
              switch_mode(fast_mode);
            }
          
          freq_intc = freqToTc(freq_inhz);
          TC_setup();        
          Serial.print("Fast Mode = ");
          Serial.println(fast_mode, DEC);      
          Serial.print("freq_inhz = ");
          Serial.println(freq_inhz, DEC);      
          Serial.print("freq_intc = ");
          Serial.println(freq_intc, DEC);      
          Serial.print("approximation = ");
          temp = tcToFreq(freq_intc);
          Serial.println(temp, DEC);      
        }
      user_intf = 0; // reset to 0 ready for the next sequence of digits
      }    
    }
  }
}

void DACC_Handler(void)
{
  if((dacc_get_interrupt_status(DACC) & DACC_ISR_ENDTX) == DACC_ISR_ENDTX) {
    ++sptr; 
    sptr &=  0x01;
    if(fast_mode == 0) 
    {
      DACC->DACC_TNPR =  (uint32_t)  Sinewave[sptr];      // next DMA buffer
      DACC->DACC_TNCR =  NWAVE;
    }
  else
    {
      DACC->DACC_TNPR =  (uint32_t)  SineFast[sptr];      // next DMA buffer
      DACC->DACC_TNCR =  NWAVE;
    }
  }
}

void setup_pio_TIOA0()  
{
  PIOB->PIO_PDR = PIO_PB25B_TIOA0;  
  PIOB->PIO_IDR = PIO_PB25B_TIOA0;  
  PIOB->PIO_ABSR |= PIO_PB25B_TIOA0;
}


void TC_setup ()
{
  pmc_enable_periph_clk(TC_INTERFACE_ID + 0 *3 + 0); 

  TcChannel * t = &(TC0->TC_CHANNEL)[0];            
  t->TC_CCR = TC_CCR_CLKDIS;                        
  t->TC_IDR = 0xFFFFFFFF;                           
  t->TC_SR;                                         
  t->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 |          
              TC_CMR_WAVE |                         
              TC_CMR_WAVSEL_UP_RC |                 
              TC_CMR_EEVT_XC0 |     
              TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
              TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR;
  
  t->TC_RC = freq_intc;
  t->TC_RA = freq_intc /2;       
  t->TC_CMR = (t->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET; 
  t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;    
}

void dac_setup ()
{
  pmc_enable_periph_clk (DACC_INTERFACE_ID) ; // start clocking DAC
  dacc_reset(DACC);
  dacc_set_transfer_mode(DACC, 0);
  dacc_set_power_save(DACC, 0, 1);            // sleep = 0, fastwkup = 1
  dacc_set_analog_control(DACC, DACC_ACR_IBCTLCH0(0x02) | DACC_ACR_IBCTLCH1(0x02) | DACC_ACR_IBCTLDACCORE(0x01));
  dacc_set_trigger(DACC, 1);
  
//  dacc_set_channel_selection(DACC, 1);
  //dacc_enable_channel(DACC, 1);
  dacc_set_channel_selection(DACC, 0);
  dacc_enable_channel(DACC, 0);

  NVIC_DisableIRQ(DACC_IRQn);
  NVIC_ClearPendingIRQ(DACC_IRQn);
  NVIC_EnableIRQ(DACC_IRQn);
  dacc_enable_interrupt(DACC, DACC_IER_ENDTX);

  DACC->DACC_TPR  =  (uint32_t)  Sinewave[0];      // DMA buffer
  DACC->DACC_TCR  =  NWAVE;
  DACC->DACC_TNPR =  (uint32_t)  Sinewave[1];      // next DMA buffer
  DACC->DACC_TNCR =  NWAVE;
  DACC->DACC_PTCR =  0x00000100;  //TXTEN - 8, RXTEN - 1.
}

 

kekia22
Offline
Зарегистрирован: 06.01.2016

dimax помогите тупому и заодно спасите мою дуе от истребления..... я уже на кувалду заглядываюсь и мысленно кайфую от того как буду наносить многочисленные удары кувалдочкой по данному чуду "DUE" сам уже 20 лет живу в макаронии,родина дуины и эта дуе как иее земляки не хило мне нервы потрепала..... 

и так задача сверх сложная...

получить синус 50/60Гц формулой,где значение отвечающее за амплитуду будет переменной.чтоб можно было в реал тайм регулировать амплитуду подавая 0  -  3,3в на один вход.

разьесню

это преобразователь напряжения 48-220в регулировка амплитуды нужно для работы обратной связи по напряжению на выходе устройства(220в)

зделал на меге,работает но только мега не успевает динамично пересчитывать формулу(необходимо для работы обратной связи) и получается классный феерверк из выходных IGBT ..... очень прошу помощи....

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

kekia22, не понятно чем помочь. Раз вы уже делали -так и перенесите свой код на Дуе и всё. Цап работает очень просто, нужно проинитить его , всего 3 строчки:

REG_PMC_PCER1|=1<<6; //включить тактирование "DACC"    
REG_DACC_CR=1; //dacc_reset(DACC);
REG_DACC_CHER=1; //channel 0 enable
И потом кидать в REG_DACC_CDR сэмпл.

А вообще я бы не советовал делал программную обратную связь, это всегда чревато "феерверком", лучше всё сделать аппаратно.

Sencis
Offline
Зарегистрирован: 26.01.2018

dimax пишет:

Частотометр с другим принципом измерения - один таймер отсчитывает  секунду, другой таймер  считает количество входных импульсов пришедших на тактовый вход за эту секунду. Точность счёта -1 Герц (без учёта  неточности кварца).  Что -бы избежать необходимости прерываний пришлось пойти на применение аппаратной петли -нужно связать эти два таймера. (Ради повышения точности измерения, -получаем полностью аппаратный частотомер, не влияющий на загрузку МК).  Пин А7 нужно соединить с пином 2.  Вход ипульсов подавать на пин А5. Считает частоту от от 1-го Герца и до... даташит говорит, цитата "In all cases, if an external clock is used, the duration of each of its levels must be longer than the peripheral clock period. The external clock frequency must be at least 2.5 times lower than the peripheral clock" то есть  по идее не более, чем 16.8 МГц , но я подавал 21МГц -отображалось верно, возможно потому, что сгенерил их на этом же МК :) . В отличие от предыдущего частотомера не измеряет скважность.

/* Частотометр для ARDUINO DUE, вариант подсчёта количества импульсов за 1 секунду
 *  вход частоты -(А5), **выход тактов сброса 1Гц (А7пин) соединить с входом сброса (2пин)*** 
*/
void setup() {
Serial.begin(115200);
REG_PMC_PCER0|=(1<<27)|(1<<28); //включить тактирование TC 0 и 1 канал 
REG_PIOB_PDR|=(1<<25);//b25 будет периферия
REG_PIOB_ABSR|=(1<<25); //периферия "Б" выбрана
REG_PIOA_PDR |= (1<<2)|(1<<4); // (pinA7, TIOA1) ,( pinA5 TCLK1)будет периферия 
REG_TC0_CMR0=(1<<14)|(1<<15)|(1<<18)|(1<<19);//конфиг генератора 1Герц
REG_TC0_RC0=42E6;
REG_TC0_CMR1 = (1<<1)|(1<<2)|(1<<8)|(1<<10)|(1<<16)|(1<<17); //конфиг счётчика импульсов
REG_TC0_CCR0=5; REG_TC0_CCR1=5;  //Обнулить счётчики и запустить таймеры.


}
void loop() {

if (REG_TC0_SR1&B10100000){Serial.print(REG_TC0_RA1); Serial.println(" Hz  "); } 
}

 

Можно по точнее "Пин А7 нужно соединить с пином 2" имеется в виду аналоговый пин? И каким образом будет работатать внешнее тактирование при лог 1 (3.3В) на А5 или можно подтянуть на землю или разницы нет?

В итоге выяснилось что на цифровой пин 2 а жаль.