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

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

Sencis ,

В принципе с соответствующей переделкой скетча можно посадить на любые свободные TIO* ноги. Я просто взял "первые с краю" ;)

Instance Signal PIO Line Peripheral Arduino pin
TC0 TIOA0 PB25 B 2
TC0 TIOA1 PA2 A A7
TC0 TIOA2 PA5 A -
TC0 TIOB0 PB27 B 13
TC0 TIOB1 PA3 A A6
TC0 TIOB2 PA6 A A4
TC2 TIOA6 PC25 B 5
TC2 TIOA7 PC28 B 3
TC2 TIOA8 PD7 B 11
TC2 TIOB6 PC26 B 4
TC2 TIOB7 PC29 B 10
TC2 TIOB8 PD8 B 12

 

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

По вашему частотометру получилось сделать тахометр на ДВС от авимодели. Едиственное контакт А5 не подтянут к земле пришлось колхозить.

marth
Offline
Зарегистрирован: 24.09.2019

Хотел попробовать программу генератор DDS, и похоже загубил DAC0 (случайно замкнул выход). DAC1 работает.

Как можно переназначить выход на DAC1 ?. Я пробовал так, но увы, не заработало. В этих регистрах пока совсем не разбираюсь 

 

REG_PIOB_OER|=1<<16; //PB16 будет выход
   REG_PIOB_PDR|=1<<16;//PB16 будет периферия

 

Сделал так, заработало на DAC1, хотя код стал менее красивым ). Синус довольно неплох, по гармоникам 0.02%

#define freq 1000.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<<16; //PB16 будет выход
 REG_PIOB_PDR|=1<<16;//PB16 будет периферия
   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
      DACC->DACC_CR = DACC_CR_SWRST ;           // Reset DACC
      DACC->DACC_MR = DACC_MR_TRGEN_DIS         // Hardware trigger disable, Free Run mode                
                  | DACC_MR_USER_SEL_CHANNEL1   // select channel 1
                  | DACC_MR_REFRESH (1)
                  | DACC_MR_STARTUP_8
                  | DACC_MR_MAXS;
      DACC->DACC_CHER = DACC_CHER_CH1; // enable channel 1 = DAC1
      
      __disable_irq();
         while(1){
      datatemp= sine_wave[(akkum+=shag)>>18];
    if(REG_DACC_ISR&1==1){ REG_DACC_CDR=datatemp;}  
  }
}
void loop(){}

 

 

marth
Offline
Зарегистрирован: 24.09.2019

Любопытно, что представленный здесь генератор синуса  с использованием ДМА, обладает немного худшими качественными характеристиками

KJloyH
Offline
Зарегистрирован: 21.03.2020

Доброе время суток. А разве нету возможность сконфигурировать так чтобы не поять внешею перемычку между пинами? Спасибо.

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

KJloyH, речь про частотометр из #41? Я позже пробовал, но нужных аппаратных меж- таймерных связей не нашёл.  Можно программными способами, но это испортит всю малину..

KJloyH
Offline
Зарегистрирован: 21.03.2020

Пока не очень хорошо разобрался в TC но всё же подразумеваю что это возможно если не сложно даташит 901 страница там вроде есть но так как не очень разобрался могу ошибаться. Вашу программу разобрал досконально много чего понял, но не все спасибо.

Alex_1978
Offline
Зарегистрирован: 21.07.2019

Доброго времени суток.
Который день ковыряюсь в описании DUE, пытаюсь код из поста 33, тот, что просто даёт синус на выход DAC, синхронизировать с PWM- меандриком. Нужно в идеале сделать ждущий мультивибратор, чтобы при появлении на ноге PWM высокого уровня, DAC0 выдал один целый период синуса, и снова ожидал. Отдельно всё разбегается.
В книжке написано, что ЦАП может работать от внешнего триггера, а для PWM-a eсть Event Line x Register, а вот как скрестить ужа с ежом мне неведомо. Кто-нибудь знает, как это работает?

#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(){}

Это бы подправить...

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

Alex_1978, данный метод синтеза DDS не подходит для вашей задачи. Нужно выталкивать каждый семпл из массива под такты таймера. Тогда синхронизация от внешнего сигнала возможна. 

Alex_1978
Offline
Зарегистрирован: 21.07.2019
 
Доброго времени суток.
dimax, большое спасибо вам за совет. Сделал меандры с использованием штатного PWM и выталкиванием массива синуса под такты таймера.
Задачка была под 50гц, выставил раз каналы и забыл, и чтоб ничего не плавало относительно друг друга. Таймер 500кГц, 2мкс., циклично прогоняется целый период синуса, массив на 10.000 элементов.
Относительные смещения каналов написаны топорненько, но главное что все заработало, и выставить можно очень точно.
Итого, 4шт. 50Гц PWM меандра c регулируемой скважностью и взаимным смещением, и синус 50Гц на ноге DAC0, может кому пригодится.
 
#include <pwm_lib.h>
#include <DueTimer.h>
using namespace arduino_due::pwm_lib;
 
int sine_long_arr = 10000;
uint16_t* sine_wave = new uint16_t[sine_long_arr]; 
uint32_t datatemp, akkum;
uint32_t pin8_status1; uint32_t pin8_status2;
 
// PWM started 9-8-6-7 pin
#define PWM_PERIOD_PIN_9 20000000//
#define PWM_DUTY_PIN_9   10000000//
 
#define PWM_PERIOD_PIN_8 2000000 //50 Hz
#define PWM_DUTY_PIN_8   1000000 // Duty cicle 50%
#define PWM_PERIOD_PIN_6 2000000//50 Hz IMP
#define PWM_DUTY_PIN_6   40000 // Duty cicle
#define PWM_PERIOD_PIN_7 2000000  // Charge diagram
#define PWM_DUTY_PIN_7   1500000// Duty cicle
 
int IMP1_offset = 63000;
int IMP2_offset = 42000;//132;
int Sine_offset = 35000;
 
 pwm<pwm_pin::PWML4_PC21> pwm_pin9;
 pwm<pwm_pin::PWML5_PC22> pwm_pin8;
 pwm<pwm_pin::PWML6_PC23> pwm_pin7;
 pwm<pwm_pin::PWML7_PC24> pwm_pin6;
 
 int i = 0; 
 void myHandler5(){
 i++; if(i>sine_long_arr){i=1;}
 datatemp= sine_wave[i];
 if(REG_DACC_ISR&1==1){ REG_DACC_CDR=datatemp; }
                  }
int var = 0;
 
void setup() {
 
 Serial.begin(9600);
 Timer5.attachInterrupt(myHandler5);
 
//Sine, DAC init
for(uint16_t n=0; n<sine_long_arr; n++){sine_wave[n]=4095*(sin(TWO_PI*float(n)/sine_long_arr)+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  
 
REG_PIOC_OWER = 0xFFFFFFFF; // Port_C ON 
REG_PIOC_OER =  0xFFFFFFFF; // Port_C is OUT
REG_PIOB_OWER = 0xFFFFFFFF; // Port_B ON
REG_PIOB_OER =  0xFFFFFFFF; // Port_B is OUT
 
pinMode(9,OUTPUT); pinMode(8,OUTPUT); pinMode(7,OUTPUT); pinMode(6,OUTPUT);
pinMode(34,INPUT); // Включаем тактирование порта C :)
 
pwm_pin9.start(PWM_PERIOD_PIN_9,PWM_DUTY_PIN_9);
pwm_pin8.start(PWM_PERIOD_PIN_8,PWM_DUTY_PIN_8);
 
while(var < IMP1_offset){ var++;} var = 0; 
pwm_pin6.start(PWM_PERIOD_PIN_6,PWM_DUTY_PIN_6);
 
while(var < IMP2_offset){ var++;} var = 0; 
pwm_pin7.start(PWM_PERIOD_PIN_7,PWM_DUTY_PIN_7);
 
while(var < Sine_offset){ var++;} var = 0; 
Timer5.attachInterrupt(myHandler5).setPeriod(2).start(); // 2мкс, 500 кГц
            }
 
void loop() {}