user87791: 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

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:

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.

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.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.

user7508: Shiny100 asked:

Does it mean Arduino will cost several microseconds executing command
like POTRA=0x1.

I tried compiling POTRA=0x1 and I got this:
ldi r24, 0x01  ; load 0x1 into register r24
out 0x02, r24  ; output register r24 to PORTA (I/O address 0x02)

These are both single cycle instructions, so the sequence takes
2 cycles, i.e. 0.125 µs at 16 MHz. Your code, however,
does a lot more that that. The macro OUTPUT_WAVE() involves reading
ten values from RAM and writing them to ten different ports. The first
call to this macro gets compiled into this:
lds r24, 0x028D ; r24 = bufferA[0]
out 0x02, r24   ; PORTA = r24
lds r24, 0x028E ; r24 = bufferA[1]
out 0x08, r24   ; PORTC = r24
lds r24, 0x028F ; r24 = bufferA[2]
sts 0x010B, r24 ; PORTL = r24
lds r24, 0x0290 ; r24 = bufferA[3]
out 0x05, r24   ; PORTB = r24
lds r24, 0x0291 ; r24 = bufferA[4]
sts 0x0108, r24 ; PORTK = r24
lds r24, 0x0292 ; r24 = bufferA[5]
out 0x11, r24   ; PORTF = r24
lds r24, 0x0293 ; r24 = bufferA[6]
sts 0x0102, r24 ; PORTH = r24
lds r24, 0x0294 ; r24 = bufferA[7]
out 0x0b, r24   ; PORTD = r24
lds r24, 0x0295 ; r24 = bufferA[8]
out 0x14, r24   ; PORTG = r24
lds r24, 0x0296 ; r24 = bufferA[9]
sts 0x0105, r24 ; PORTJ = r24

The out instruction is still single cycle, but lds (load from
memory) and sts (store to memory) take two cycles each. You may notice
that only ports A through F are accessed with the out instruction.
This is because they are mapped in the I/O address space of the
microcontroller. The other four ports are accessed using the slower
sts instruction on memory-mapped addresses.
If you count your cycles, you should get 34 cycles for the whole
sequence, which is 2.125 µs at 16 MHz. Ideally, you would like
this to take 2.5 µs (1/10 of a cycle of a 40 kHz signal). You
may notice that the code you took inspiration from has a few
instructions between successive calls to OUTPUT_WAVE(). It looks to me
like those were carefully timed to get as close as possible to
2.5 µs per phase. This approach is obviously fragile: any tiny
change in the code, or even a compiler upgrade, can throw off your
carefully timed code.
Edit: The second question, if I understand it correctly, is about
the change in duty cycle. The waveforms have a nominal duty cycle of
50%: the signal is LOW over 5 time slots (5/10 of the cycle), then
HIGH for the next 5 time slots. The time slots, however, do not
have all the same length. The first nine last 2.125 µs each. The
last one, however, is somewhat longer, because it takes the duration of
the code handling the serial port, and the two cycles of goto LOOP;.
If the longer time slot happens when the output is HIGH, you get an
actual duty cycle higher than 50%. If it happens when it is HIGH, you
get a shorter duty cycle, like in your “shift wave failed” example.

87791: <p>I want to use Arduino-mega generate multiple square wave signal,the siganl is 40kHz and it can be used to drive ultrasonic transducer.</p>
<p>So,I use the trategy in article &quot;<a href="https://ieeexplore.ieee.org/document/8094247" rel="nofollow noreferrer">Ultraino: An Open Phased-Array System for
Narrowband Airborne Ultrasound Transmission</a>&quot;,which apply 10 bit signal with sequence of '0' or '1' in PORTA,PORTC...etc to get a square wave signal like Fig 1.</p>
<p><a href="https://i.stack.imgur.com/xAe7X.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xAe7X.jpg" alt="Fig.1 square wave signal" /></a></p>
<p>Fig.1 square wave signal</p>
<hr />
<p>Then I change the sequence pattern to shift phase,and just only 10 phases,some problem happen.</p>
<p>I am curious about the principle of this method:</p>
<ol>
<li><p>Why the sequence can generate signal with 40kHz?Does it mean Arduino will cost serval microseconds executing command like <code>POTRA=0x1</code>. I try to change the length of the array,it will no longer generate the square wave well.</p>
</li>
<li><p>When I execute the shift function <code>shiftPhase</code>,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?</p>
</li>
</ol>
<p><a href="https://i.stack.imgur.com/8xGIO.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8xGIO.jpg" alt="Fig.2 shift wave success" /></a>
Fig.2 shift wave success</p>
<hr />
<p><a href="https://i.stack.imgur.com/8F3p9.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8F3p9.jpg" alt="Fig.3 shift wave failed" /></a>
Fig.3 shift wave failed</p>
<hr />
<p>the code I use is:</p>
<pre><code>#include &lt;avr/sleep.h&gt;
#include &lt;avr/power.h&gt;
#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__ (&quot;nop&quot;)
#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=&quot;&quot;;
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&lt;10;i++)
  {
    q[i]=p[i*inter];
  }
  for(int i=0;i&lt;10;i++)
  {
    p[i*inter]=(q[(i+stepsize+10)%10]&amp;id)|(mask&amp;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 &lt; (N_PATTERNS * N_DIVS * N_PORTS); ++i) {
    bufferA[i] = bufferB[i] = 0;
  }
   for (int i = 0; i &lt; 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 = &amp; bufferA[0];
  byte* emittingPointerL = &amp; 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=&quot;&quot;;
      str=char(Serial.read());
      Serial.println(str);
      if(str==&quot;1&quot;)
      {
        shiftPhase(bufferA,10,10,1,0x1);
      }
      if(str==&quot;2&quot;)
      {
        shiftPhase(bufferA,10,10,-1,0x1);
      }
    }
 while(Serial.read()&gt;=0){}
  goto LOOP;

}

void loop() {}
</code></pre>
<p>Thanks a lot!</p>
<p>The code of the article can be see in <a href="https://github.com/asiermarzo/Ultraino/blob/master/DriverBoards/ArduinoMega64/firmware/DriverMEGAStatic/DriverMEGAStatic.ino" rel="nofollow noreferrer">link</a>.</p>
 7508: <p>Shiny100 asked:</p>
<blockquote>
<p>Does it mean Arduino will cost several microseconds executing command
like <code>POTRA=0x1</code>.</p>
</blockquote>
<p>I tried compiling <code>POTRA=0x1</code> and I got this:</p>
<pre class="lang-lisp prettyprint-override"><code>ldi r24, 0x01  ; load 0x1 into register r24
out 0x02, r24  ; output register r24 to PORTA (I/O address 0x02)
</code></pre>
<p>These are both single cycle instructions, so the sequence takes
2 cycles, i.e. 0.125 µs at 16 MHz. Your code, however,
does a lot more that that. The macro <code>OUTPUT_WAVE()</code> involves reading
ten values from RAM and writing them to ten different ports. The first
call to this macro gets compiled into this:</p>
<pre class="lang-lisp prettyprint-override"><code>lds r24, 0x028D ; r24 = bufferA[0]
out 0x02, r24   ; PORTA = r24
lds r24, 0x028E ; r24 = bufferA[1]
out 0x08, r24   ; PORTC = r24
lds r24, 0x028F ; r24 = bufferA[2]
sts 0x010B, r24 ; PORTL = r24
lds r24, 0x0290 ; r24 = bufferA[3]
out 0x05, r24   ; PORTB = r24
lds r24, 0x0291 ; r24 = bufferA[4]
sts 0x0108, r24 ; PORTK = r24
lds r24, 0x0292 ; r24 = bufferA[5]
out 0x11, r24   ; PORTF = r24
lds r24, 0x0293 ; r24 = bufferA[6]
sts 0x0102, r24 ; PORTH = r24
lds r24, 0x0294 ; r24 = bufferA[7]
out 0x0b, r24   ; PORTD = r24
lds r24, 0x0295 ; r24 = bufferA[8]
out 0x14, r24   ; PORTG = r24
lds r24, 0x0296 ; r24 = bufferA[9]
sts 0x0105, r24 ; PORTJ = r24
</code></pre>
<p>The <code>out</code> instruction is still single cycle, but <code>lds</code> (load from
memory) and <code>sts</code> (store to memory) take two cycles each. You may notice
that only ports A through F are accessed with the <code>out</code> instruction.
This is because they are mapped in the I/O address space of the
microcontroller. The other four ports are accessed using the slower
<code>sts</code> instruction on memory-mapped addresses.</p>
<p>If you count your cycles, you should get 34 cycles for the whole
sequence, which is 2.125 µs at 16 MHz. Ideally, you would like
this to take 2.5 µs (1/10 of a cycle of a 40 kHz signal). You
may notice that the code you took inspiration from has a few
instructions between successive calls to <code>OUTPUT_WAVE()</code>. It looks to me
like those were carefully timed to get as close as possible to
2.5 µs per phase. This approach is obviously fragile: any tiny
change in the code, or even a compiler upgrade, can throw off your
carefully timed code.</p>
<p><strong>Edit</strong>: The second question, if I understand it correctly, is about
the change in duty cycle. The waveforms have a <em>nominal</em> duty cycle of
50%: the signal is LOW over 5 time slots (5/10 of the cycle), then
HIGH for the next 5 time slots. The time slots, however, do not
have all the same length. The first nine last 2.125 µs each. The
last one, however, is somewhat longer, because it takes the duration of
the code handling the serial port, and the two cycles of <code>goto LOOP;</code>.
If the longer time slot happens when the output is HIGH, you get an
actual duty cycle higher than 50%. If it happens when it is HIGH, you
get a shorter duty cycle, like in your “shift wave failed” example.</p>
