Generar doble frecuencia en un mismo pin con el DUE

Hola a todos y gracias de antemano por vuestro preciado tiempo.

Estoy intentando generar dos frecuencias en el mismo Pin con el Due, dos frecuencias me refiero a una portadora de baja frecuencia de 3200hz y otra de alta frecuencia de 819200hz.

La de alta frecuencia generarla mientras la de baja frecuencia este en alto o en pulso, cuando la de baja frecuencia este en bajo o sin pulso en ese momento la de alta frecuencia tambien esté en bajo o sin pulso.

Me gustaría poder configurar la frecuencia y el ancho de pulso de las 2, sería la repanocha.

Estoy intentándolo con tres códigos diferentes que os paso a continuación, pero no lo consigo

void setup() {
  
int32_t mask_PWM_pin = digitalPinToBitMask(7);

REG_PMC_PCER1 = 1<<4;                 // activate clock for PWM controller
REG_PIOC_PDR |= mask_PWM_pin;    // activate peripheral functions for pin (disables all PIO functionality)
REG_PIOC_ABSR |= mask_PWM_pin;  // choose peripheral option B   
REG_PWM_CLK = 0;                          // choose clock rate, 0 -> full MCLK as reference 84MHz
REG_PWM_CMR6 = 0<<9;                 // select clock and polarity for PWM channel (pin7) -> (CPOL = 0)
REG_PWM_CPRD6 = 80;                  // initialize PWM period -> T = value/84MHz (value: up to 16bit), value=80 -> 1.05MHz 
REG_PWM_CDTY6 = 40;                   // initialize duty cycle, REG_PWM_CPRD6 / value = duty cycle, for 80/40 = 50%
REG_PWM_ENA = 1<<6;                  // enable PWM on PWM channel (pin 7 = PWML6)

delay(10);

}

void loop() 
{

}

Este es otro de los códigos:

void setup() 
{
  // PWM Set-up on pin: DAC1
  
  REG_PMC_PCER1 |= PMC_PCER1_PID36;                     // Enable PWM 
  REG_PIOB_ABSR |= PIO_ABSR_P16;                        // Set PWM pin perhipheral type A or B, in this case B
  REG_PIOB_PDR |= PIO_PDR_P16;                          // Set PWM pin to an output
  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42);     // Set the PWM clock rate to 2MHz (84MHz/42) 
  REG_PWM_CMR0 = PWM_CMR_CALG | PWM_CMR_CPRE_CLKA;      // Enable dual slope PWM and set the clock source as CLKA
  REG_PWM_CPRD0 = 20000;                                // Set the PWM frequency 2MHz/(2 * 20000) = 50Hz 
  REG_PWM_CDTY0 = 1500;                                 // Set the PWM duty cycle to 1500 - centre the servo
  REG_PWM_ENA = PWM_ENA_CHID0;                          // Enable the PWM channel     
}

void loop() {}

y este es el tercer codigo:

#include <Arduino.h>
 
uint32_t pwmPin = 8;
uint32_t maxDutyCount = 2;
uint32_t clkAFreq = 21000000ul;
uint32_t pwmFreq = 21000000ul; 
 
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(0);
}
 
void loop() 
{
}

Espero haberme explicado lo suficiente, lo que intento es con PWM en el mismo pin generar y controlar dos frecuencias, una base de frecuencia baja y una de frecuencia alta.

UN MILLON DE GRACIAS POR ADELANTADO POR LA AYUDA RECIBIDA GRACIAS

Después de darle un millon de vueltas creo que la solución sería crear una interrupción en la baja frecuencia, que os parece?

Alguien puede ayudarme por favor?

Estoy con las interrupciones más liado que el pelo de una gitana.

La alta frecuencia se como generarla, lo que no me aclaro es con la interrupción de tiempo para generar la frecuencia baja.

Me falta crear una interrupción de tiempo para interrumpir la alta frecuencia al periodo deseado de la baja frecuencia, no se si me he explicado lo suficiente. Como una portadora de unos 3khz que cuando está en pulso este pulso es de 800khz. Mil gracias por adelantado.

Se entiende perfectamente pero resonderte es dificil porque hay que dedicarte tiempo para no decir cualquier cosa.
En el mundo AVR esta todo mas decantado que en el mundo SAM.
Si me das un tiempito lo pruebo a ver.

Si fuese capaz de contar los ciclos del reloj y almacenarlos en una variable, podría compararlos con otra variable configurada con un valor para generar el ancho de pulso de la alta frecuencia, entonces cortaría el pulso y volvería a contar los ciclos sin pulso hasta terminar el periodo de la frecuencia.

Dos variables configurables compararían y accionarían el PWM, una el ancho de pulso y la otra el no pulso o parte del periodo sin pulso.

Por ejemplo tengo una variable (cofigurable desde el puerto serie por ejemplo) llamada ALTA_FRECUENCIA que determina el periodo total (la longitud del pulso y el no pulso) el tiempo cuando el pin esta en alto más el tiempo cuando el pin está en bajo.

Luego otra variable llamada ANCHO_PULSO_1 que determina los ciclos de reloj que tiene que estar el pin en alto.

Contando y almacenando el numero de ciclos del reloj (o como se llamen) podría compararlos con la variable ANCHO_PULSO_1 y cuando fuese la cantidad deseada poner en off el pin (sin pulso) los ciclos necesarios hasta igualar la variable ALTA_FRECUENCIA.

Repetirlo hasta llegar al valor de otra variable llamada por ejemplo ANCHO_PULSO_2 que es la que determinaría el ancho de pulso de la baja frecuencia, que junto con otra variable llamada BAJA_FRECUENCIA determinarían el periodo de la baja frecuencia.

Entonces tendría un pulso de baja frecuencia donde su pulso son los micropulsos de la alta frecuencia.

Gracias por vuestras aportaciones.

?

?

Hola Ibruno
Te voy a responder como lo hago siempre. En este foro nadie cobra por ayudar a otros, todos los hacen de muy buena onda y cuando tienen tiempo. Algunos hasta le roban tiempo a la familia para responder acá.
Por favor, se paciente. Además, como ya dijo Surbyte, en el mundo de SAM aún no se tiene mucha experiencia, tal vez de haber preguntado por una MEGA o cualquier otra placa que utilice ATM ya tendrías tu respuesta. Aunque dudo que se pueda hacer con una MEGA lo que tu quieres hacer con una DUE.
De nuevo te pido que seas paciente, ya que no necesitas hacer mensajes de un solo carácter, el signo de interrogación, porque parece que fueses nuestro jefe y estés pidiendo el trabajo para ahora mismo.
Saludos!

Tienes toda la razón Hector, mil disculpas si ha dado esa impresión, no era mi intención molestar con el comentario del ?, puse el interrogante para no cansaros con palabras ya que me enrollo como una persiana jajaj, solo eso. Gracias por el toque no volverá a ocurrir.

:wink:

Me han enviado esta contestación pero me suena a chino profundo, os lo reenvío por si os da alguna pista:

Hola ibruno,

Disculpa, no he tenido tiempo para responderte antes.

El problema que planteas puedes resolverlo utilizando la librería pwm_lib (GitHub - antodom/pwm_lib: This is a C++ library to abstract the use of the eight hardware PWM channels available on Arduino DUE's Atmel ATSAM3X8E microcontroller.) y la librería tc_lib (GitHub - antodom/tc_lib: This is a library to take advantage of different functionalities available on Timer Counter (TC) modules in Arduino Due's Atmel ATSAM3X8E microcontrollers).

Utilizaría un objeto pwm de pwm_lib para generar la salida PWM con la frecuencia que comentas, evidentemente con un valor de duty (ciclo de trabajo) concreto.

Luego utilizaría un objecto action de la librería tc_lib, esta librería te permite manipular los canales de módulos temporizadores del ATMSAM38XE. Tienes un ejemplo de cómo utilizar un objeto action. Básicamente puedes asociar un callback que se ejecuta en tu programa con el periodo que tu establezcas. En este caso ahí en el callback con el periodo que te interese pones el duty a 0 cuándo toque, y cuándo tengas que tener PWM el duty concreto que te interese.

Esta sería un forma fácil de resolverlo.

Si necesitas eficiencia, y no desperdiciar un módulo TC para controlar la salida PWM, puedes aprovechar una interrupción asociada al PWM (es posible asociar una interrupción cada vez que se completa un periodo de PWM, por ejemplo) para desactivar la salida PWM, o utilizar los comparadores disponibles para cada canal, etc. Esta funcionalidad me temo que no está disponible en pwm_lib y tendrías que implementarla tú directamente. Ahora bien, entiendo que sería la más eficiente, sobre todo en términos de aprovechamiento de los recursos disponibles.

Bueno, pues eso, espero que te sirva :slight_smile:

Y tambien el mensaje siguiente, que conste que le estoy muy agradecido a Antodom pero todavía soy incapaz de conseguirlo y mira que le he echado horas...

Hola nuevamente Bruno,

Por partes :slight_smile:

Me temo que no tengo ningún ejemplo que haga lo que quieres hacer, en cualquier caso creo que modificando alguno de los ejemplos disponibles en pwm_lib (GitHub - antodom/pwm_lib: This is a C++ library to abstract the use of the eight hardware PWM channels available on Arduino DUE's Atmel ATSAM3X8E microcontroller.) y en tc_lib (GitHub - antodom/tc_lib: This is a library to take advantage of different functionalities available on Timer Counter (TC) modules in Arduino Due's Atmel ATSAM3X8E microcontrollers), y combinándolos, puedes llegar fácilmente a dónde quieres.

Lo primero que haría es utilizar el ejemplo basic_test.ino que viene con pwm_lib, lo adaptaría para general la señal de PWM de 830 kHz que quieres generar. Con esto ya tienes medio problema resuelto.

Luego utilizaría el ejemplo action_test.ino que viene con tc_lib y lo modificaría para que se llamara a una acción (un callback) con la frecuencia con la que quieres modular la señal de PWM. Una vez esto te funcione ya tienes la segunda parte del problema resuelto.

Lo último es combinar en un mismo programa ambas partes, de manera que en la acción pongas el duty a 0 para poner el PWM a cero, o al valor de duty que te interese cuando quieres que la señal de PMW se genere.

Con esto creo que tendrías lo que quieres. Sería cuestión de hacerlo y probarlo.

Confío en que ahora suene menos a chino :wink: