Use Arduino MEGA generate 40kHz multiple square wave signal with 10 phase

I want to use Arduino-mega generate multiple square wave signal,the siganl is 40kHz and it can be used to drive ultrasonic transducer.

So,I use the trategy in article "Ultraino: An Open Phased-Array System for
Narrowband Airborne Ultrasound Transmission
",which apply 10 bit signal with sequence of '0' or '1' in PORTA,PORTC...etc to get a square wave signal like Fig 1.

Fig.1 square wave signal

Fig.1 square wave signal


Then I change the sequence pattern to shift phase,and just only 10 phases,some problem happen.

I am curious about the principle of this method:

  1. Why the sequence can generate signal with 40kHz?Does it mean Arduino will cost serval microseconds executing command like POTRA=0x1. I try to change the length of the array,it will no longer generate the square wave well.

  2. When I execute the shift function shiftPhase,it have 10 phase.In 5 phase it will move the square wave like Fig.2,the other 5 phase will be like Fig3,the duty of square wave is changed,just like inverted.So,how does it happen,just with change the sequence of 0,1?

Fig.2 shift wave success
Fig.2 shift wave success


Fig.3 shift wave failed
Fig.3 shift wave failed


the code I use is:

#include <avr/sleep.h>
#include <avr/power.h>
#define N_PATTERNS 1
#define N_PORTS 10
#define N_DIVS 10
#define COMMAND_SWITCH 0b00000000
#define COMMAND_DURATION 0b00110000
#define MASK_DURATION 0b00111111
#define COMMAND_COMMITDURATIONS 0b00010000

#define WAIT(a) __asm__ __volatile__ ("nop")
#define OUTPUT_WAVE(pointer, d)  PORTA = pointer[d*N_PORTS + 0]; PORTC = pointer[d*N_PORTS + 1]; PORTL = pointer[d*N_PORTS + 2]; PORTB = pointer[d*N_PORTS + 3]; PORTK = pointer[d*N_PORTS + 4]; PORTF = pointer[d*N_PORTS + 5]; PORTH = pointer[d*N_PORTS + 6];  PORTD = pointer[d*N_PORTS + 7]; PORTG = pointer[d*N_PORTS + 8]; PORTJ = pointer[d*N_PORTS + 9]
static byte bufferA[N_PATTERNS * N_DIVS * N_PORTS];
static byte bufferB[N_PATTERNS * N_DIVS * N_PORTS];
static byte animation[100] = {
                            0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
                            };

String str="";
void shiftPhase(byte* p,int len,int inter,int stepsize,byte id)
{
  byte mask=0xff-id;
  byte q[10]={0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
  for(int i=0;i<10;i++)
  {
    q[i]=p[i*inter];
  }
  for(int i=0;i<10;i++)
  {
    p[i*inter]=(q[(i+stepsize+10)%10]&id)|(mask&q[i]);
  }
}

void setup()
{
  //set as output ports A C L B K F H D G J
  DDRA = DDRC = DDRL = DDRB = DDRK = DDRF = DDRH = DDRD = DDRG = DDRJ = 0xFF;
  //low signal on all of them
  PORTA = PORTC = PORTL = PORTB = PORTK = PORTF = PORTH = PORTD = PORTG = PORTJ = 0x00;
  //clear the buffers
  for (int i = 0; i < (N_PATTERNS * N_DIVS * N_PORTS); ++i) {
    bufferA[i] = bufferB[i] = 0;
  }
   for (int i = 0; i < 100; ++i)
   {
      bufferA[i] =  animation[i];
   }

  // disable everything that we do not need
  ADCSRA = 0;  // ADC
  power_adc_disable ();
  power_spi_disable();
  power_twi_disable();
  power_timer0_disable();
  power_usart1_disable();
  power_usart2_disable();


  Serial.begin(9600);

  byte bReceived = 0;
  bool byteReady = false;
  bool emittingA = true;
  byte* emittingPointerH = & bufferA[0];
  byte* emittingPointerL = & bufferA[N_PORTS * N_DIVS / 2];
  
LOOP:
  OUTPUT_WAVE(emittingPointerH, 0);
  OUTPUT_WAVE(emittingPointerH, 1);
  OUTPUT_WAVE(emittingPointerH, 2);
  OUTPUT_WAVE(emittingPointerH, 3);
  OUTPUT_WAVE(emittingPointerH, 4);
  OUTPUT_WAVE(emittingPointerL, 0);
  OUTPUT_WAVE(emittingPointerL, 1);
  OUTPUT_WAVE(emittingPointerL, 2);
  OUTPUT_WAVE(emittingPointerL, 3);
  OUTPUT_WAVE(emittingPointerL, 4); 

  byteReady = Serial.available(); 
  if(byteReady!=0)
  {
      str="";
      str=char(Serial.read());
      Serial.println(str);
      if(str=="1")
      {
        shiftPhase(bufferA,10,10,1,0x1);
      }
      if(str=="2")
      {
        shiftPhase(bufferA,10,10,-1,0x1);
      }
    }
 while(Serial.read()>=0){}
  goto LOOP;

}

void loop() {}

Thanks a lot!

The code of the article can be see in link.

Shift what? By 10 bananas?

You can use any hardware timer to produce up to 3 phase shifted rectangle signals using CTC mode.

@shiny100
You don't need this method .
as @DrDiettrich said, you can easily generate the pair of phase-shifted signals with using the 16bit hardware timer. You give about 200 steps of phase shift for 40KHz signal

Just the method in the paper

The code seems to be generating 80 output signals so I don't think hardware timers are going to do the job directly.

Thanks! I want to independently control 8 pairs of ultrasonic transducer at the same time, so I need 8 pairs of signals. I wonder whether the hardware timer can work.

You can generate as much pairs, as many timers are in the selected controller. Arduino Mega has two 8bit timers and four 16bit

OK!Are there any relevant reference examples.Is this relvant to the hardware timer ?

Yes, at first look it is what you need, but for Uno/Nano. For Mega you will have to change some settings

Thanks a lot! I'll have a try.
(Maybe a new difficulty will emerge :joy:

This can also be achieved by 10 8-bit shift registers.

I find Arduino mega have 15 PWM pin like OC0A,OC0B,OC0C....OC5A,OC5B,OC5C.Does it mean I can just create no more than 15 square wave in CTC mode in these pin?Other pin can't be used.I am a rookie :joy:

To create a PAIR of signals with phase shift you need a two PWM outputs attached to the same timer. So on Mega with its six (if I dont forget anything) timers you can create up to 6 pairs of phase shifted signals.

Right. In CTC mode all 3 channels of a timer can produce phase shifted square waves.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.