Go Down

Topic: 5 MHz signal from Due (Read 801 times) previous topic - next topic

weird_dave

Any chance you could extend the command to accept 32 clocks? You could then use the SPI controller.

I suspect the clock doesn't need to be 50/50, usually the data is sampled on one of the edges (the falling edge in your example would be what I would expect the device to use), as long as the on or off time isn't shorter than 100ns, any method you choose should work.

What methods have you actually used to communicate with the device, and what were the results? Note that if the device samples on the rising edge, the picture of the waveform you think you want, isn't.

paxtakor22

#16
Mar 07, 2019, 12:23 am Last Edit: Mar 07, 2019, 12:29 am by paxtakor22
If a PWM PDC DMA is used, the "clock pin" frequency will be 84 MHz/8/2 = 5250000 Hz. If a 5% error is still acceptable, that's OK.

Edit: I took some more time to explore a solution since a 5 MHz interrupt frequency is an issue.

1/ It's possible to output a 4.94 quasi square wave on a "clock pin", say PWM channel 1 PWMH1

2/ As MartinL suggested, use PWM channel 0 PWMH0 to output 26 signals on a "data pin" at a 4.94 MHz frequency by using this channel as a synchro channel but only with itself (only one interruption after 26 ouput signals), and enable PWM channel 0 and channel 1 at the same time to be synchro.

3/ Once the 26 signals have been sent by PWM channel 1, disable this channel inside the interrupt handler, but keep PWM channel 0 enabled.


I guess after that you will have to decipher a receiving message from the device and attachinterrupt() won't be fast enough to decipher 5 MHz  input signals....
Sorry, im not following.

Do you mean something like this?


Code: [Select]


void setup()
{
  //pinMode(LED_BUILTIN, OUTPUT);
  pinMode(24, OUTPUT);

  REG_PMC_PCER1 |= PMC_PCER1_PID36;                   // PWM power ON

  REG_PIOC_PDR |= PIO_PDR_P3;                         // Set PWM pin to a peripheral
  REG_PIOC_ABSR |= PIO_PC3B_PWMH0;                    // Set PWM pin peripheral type B for PWMH0 (Arduino pin 35)

  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);    // select Frequency for clock A: Mck = 84 MHz

  REG_PWM_CMR0 = PWM_CMR_CPRE_CLKA;      // The period is left aligned, clock source as CLKA on channel 0
  REG_PWM_CPRD0 = 17;                    // Set the PWM frequency 84 MHz/PWM_CPRD = 4941176 Hz
  REG_PWM_CDTY0 = 8;                     // Set the PWM duty cycle = (CPRD/CDTY) * 100 %


  REG_PIOA_PDR |= PIO_PDR_P19; // pin 42

  REG_PIOA_ABSR |= PIO_PA19B_PWMH1; // pin 42  

  REG_PWM_CMR1 = PWM_CMR_CPRE_CLKB;    

  REG_PWM_CPRD1 = 1;                            

  REG_PWM_CDTY1 = 0; // 100%    



  REG_PWM_IER1 = PWM_IER1_CHID0;                      // Interrupt on PWM Channel 0 counter
  NVIC_EnableIRQ(PWM_IRQn);                           // Enable interrupt

  REG_PWM_SCM |= PWM_SCM_SYNC0; // sync ch 0

  REG_PWM_ENA = PWM_ENA_CHID0|PWM_ENA_CHID01;                   // Enable PWM channel 0 and 1
}


void loop()
{
}

void PWM_Handler()
{
  
  REG_PWM_ISR1;      // Clear status register
  //REG_PIOB_ODSR ^= PIO_ODSR_P27;
  //REG_PIOA_ODSR ^= PIO_ODSR_P15;
  
  REG_PWM_DIS = PWM_ENA_CHID0;
 
}




Any chance you could extend the command to accept 32 clocks? You could then use the SPI controller.

I suspect the clock doesn't need to be 50/50, usually the data is sampled on one of the edges (the falling edge in your example would be what I would expect the device to use), as long as the on or off time isn't shorter than 100ns, any method you choose should work.

What methods have you actually used to communicate with the device, and what were the results? Note that if the device samples on the rising edge, the picture of the waveform you think you want, isn't.
The documentation on this signal says that the "Polarity" is positive. I'm not sure what that means.

We have an ancient tester that can test these devices using some obsolete National Instruments card. I probed the data and clock lines on this tester and saw a 5MHz clock signal in sync with the data on a rising edge so i think it samples on the falling edge.

I cannot extend to 32.

ard_newbie

#17
Mar 07, 2019, 06:32 am Last Edit: Mar 07, 2019, 07:14 am by ard_newbie
A sketch for the Clock pin and the Data pin (I took as an example for the Data pin output 101010.....). Note that the 26 samples of the Data pin are output only once in this example, whereas the clock pin runs at 50% duty cycle forever:

Code: [Select]

/*******************************************************************************************/
/*  Synchro channel PWMH0 ONLY with PDC DMA trigger on Compare for the Data pin            */
/*                PWM channel 1 50% duty cycle for the clock pin                           */
/*******************************************************************************************/

// Pin 35 (PC3)is the data pin
// Pin 37 (PC5)is the clock pin

#define BufferSize  (26)                // Sample number (a power of 2 is better)
#define PERIOD_VALUE (17)               // For  4.94 MHz
#define NbCh      (1)                   // Only channel 0 ---> Number of channels = 1

#define DUTY_BUFFER_LENGTH      (BufferSize * NbCh) // Half words

uint16_t Duty_Buffer[DUTY_BUFFER_LENGTH];
uint16_t Duty_Buffer_Null[DUTY_BUFFER_LENGTH];
uint16_t Buffer_Duty[BufferSize];

void setup () {

  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                            // PWM controller power ON
  PWM->PWM_CLK = PWM_CLK_PREA(0b0000) | PWM_CLK_DIVA(1);        // Set the PWM clock rate for 84 MHz/1

  /*****************  Data pin programming       *********************/
  // PWMH0 on PC3, peripheral type B
  PIOC->PIO_PDR |= PIO_PDR_P3;                                 // Set PWM pin to a peripheral
  PIOC->PIO_ABSR |= PIO_PC3B_PWMH0;                            // Set PWM pin peripheral type B for PWMH1 (Arduino pin 35)

  // Set synchro channels list : Channel 0
  PWM->PWM_DIS = PWM_DIS_CHID0;

  PWM->PWM_SCM  = PWM_SCM_SYNC0 |      // Add SYNCx accordingly, at least SYNC0
                  PWM_SCM_UPDM_MODE2;  //Automatic write of duty-cycle update registers by the PDC DMA

  // Set the PWM Reference channel 0 i.e. : Clock/Frequency/Alignment
  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA;               // The period is left aligned, clock source as CLKA on channel 0
  PWM->PWM_CH_NUM[0].PWM_CPRD = PERIOD_VALUE;                   // Set the PWM frequency (84MHz/1)/PERIOD_VALUE Hz


  // Fill duty cycle buffer for channels 0, x, y ...
  // Buffer_Duty is a buffer of Half Words(H_W) composed of N lines which structure model for each duty cycle update is :
  // [ H_W: First synchro channel 0 duty cycle **Mandatory** ]/[ H_W: Second synchro channel duty cycle ] ... and so on

  for (int i = 0; i < BufferSize / 2; i++)     // Data pin output example: Buffer = 10101010 ....
  {
    Buffer_Duty[2 * i] = 4095;
    Buffer_Duty[2 * i + 1] = 0;
  }
  for (int i = 0; i < DUTY_BUFFER_LENGTH ; i++)
  {
    Duty_Buffer_Null[i] = 0;
  }
  for (int i = 0; i < DUTY_BUFFER_LENGTH ; i++) // Data pin output example: Buffer = 10101010 ....
  {
    Duty_Buffer[i] = Buffer_Duty[i];
  }
  

  PWM->PWM_TPR  = (uint32_t)Duty_Buffer;        // FIRST DMA buffer
  PWM->PWM_TCR  = DUTY_BUFFER_LENGTH;           // Number of Half words
  PWM->PWM_TNPR = (uint32_t)Duty_Buffer_Null;        // Next DMA buffer
  PWM->PWM_TNCR = DUTY_BUFFER_LENGTH;
  PWM->PWM_PTCR = PWM_PTCR_TXTEN;               // Enable PDC Transmit channel request

  // Set Interrupt events
  PWM->PWM_IER2 = PWM_IER2_WRDY;                //Write Ready for Synchronous Channels Update Interrupt Enable
  NVIC_EnableIRQ(PWM_IRQn);
  /*************************************************************************/

  /*******************       Clock pin programming        ***********/
  PIOC->PIO_PDR |= PIO_PDR_P5;                         // Set PWM pin to a peripheral
  PIOC->PIO_ABSR |= PIO_PC5B_PWMH1;                    // Set PWM pin peripheral type B for PWMH1 (Arduino pin 37)

  PWM->PWM_DIS = PWM_DIS_CHID1;

  PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_CPRE_CLKA;      // The period is left aligned, clock source as CLKA on channel 1
  PWM->PWM_CH_NUM[1].PWM_CPRD = PERIOD_VALUE;          // Set the PWM frequency 84 MHz/PWM_CPRD = 4.94 MHz
  PWM->PWM_CH_NUM[1].PWM_CDTY = (uint8_t)(PERIOD_VALUE/2);        // Set the PWM duty cycle = (CPRD/CDTY) * 100 %
  /***********************************************************/

  PWM->PWM_ENA = PWM_ENA_CHID0 |                       // Enable PWM channel 0 and channel 1 at the same time
                 PWM_ENA_CHID1;
}

void loop() {
}

void PWM_Handler() {  // move PDC DMA pointers to next buffer

  PWM->PWM_ISR2;      // Clear status register

  PWM->PWM_TNPR = (uint32_t)Duty_Buffer_Null;
  PWM->PWM_TNCR = DUTY_BUFFER_LENGTH;

}






Go Up