Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

12 simultaneous & unique frequencies (PWM)

Status
Not open for further replies.
It would be interesting to see the disassemble of your new C program. Would you mind posting it here?

This is after the decrements.

Code:
        if (counter1 == 0) {counter1 = 112; fbi(PORTB, 0);}
00000097  CPSE R2,R1        Compare, skip if equal
00000098  RJMP PC+0x0006        Relative jump
00000099  LDI R25,0x70        Load immediate
0000009A  MOV R2,R25        Copy register
0000009B  IN R25,0x05        In from I/O location
0000009C  EOR R25,R24        Exclusive OR
0000009D  OUT 0x05,R25        Out to I/O location
 
I modified to code to:

C:
    while(1)
    {             
        /* Check if counter is over the top */
        if (counter1-- == 0) {counter1 = 112; fbi(PORTB, 0);}
        if (counter2-- == 0) {counter2 = 119; fbi(PORTB, 0);}
        if (counter3-- == 0) {counter3 = 126; fbi(PORTB, 0);}
        if (counter4-- == 0) {counter4 = 134; fbi(PORTB, 0);}
        if (counter5-- == 0) {counter5 = 141; fbi(PORTB, 0);}
        if (counter6-- == 0) {counter6 = 150; fbi(PORTB, 0);}
        if (counter7-- == 0) {counter7 = 159; fbi(PORTB, 0);}
        if (counter8-- == 0) {counter8 = 168; fbi(PORTB, 0);}
        if (counter9-- == 0) {counter9 = 178; fbi(PORTB, 0);}
        if (counter10-- == 0) {counter10 = 189; fbi(PORTB, 0);}
        if (counter11-- == 0) {counter11 = 200; fbi(PORTB, 0);}
        if (counter12-- == 0) {counter12 = 212; fbi(PORTB, 0);}
    }

That is a tad faster.. 45 cycles at best.
 
Last edited:
I think you need:

C:
if (--counter1 == 0) {counter1 = 112; fbi(PORTB, 0);}

I bet this time it'll be almost identical to the assembler.
 
No..
if(counter1-- ==0){counter1 =112; fbi(PORTB,0);}

produces more efficient code than
if(--counter1 ==0){counter1 =112; fbi(PORTB,0);}

62 cycles best case.
 
if (--counter3 == 0) {counter3 = 126; fbi(PORTB, 0);}
Code:
        if (--counter3 == 0) {counter3 = 126; fbi(PORTB, 0);}
00000091  MOV R25,R4        Copy register
00000092  SUBI R25,0x01        Subtract immediate
00000093  BRNE PC+0x02        Branch if not equal
00000094  RJMP PC+0x0046        Relative jump
00000095  MOV R4,R25        Copy register

...
        if (--counter3 == 0) {counter3 = 126; fbi(PORTB, 0);}
000000D6  MOV R25,R4        Copy register
000000D7  SUBI R25,0x01        Subtract immediate
000000D8  BREQ PC+0x02        Branch if equal
000000D9  RJMP PC-0x0044        Relative jump
000000DA  LDI R26,0x7E        Load immediate
000000DB  MOV R4,R26        Copy register
000000DC  IN R25,0x05        In from I/O location
000000DD  EOR R25,R24        Exclusive OR
000000DE  OUT 0x05,R25        Out to I/O location

if (counter3-- == 0) {counter3 = 126; fbi(PORTB, 0);}
Code:
        if (counter3-- == 0) {counter3 = 126; fbi(PORTB, 0);}
0000008F  TST R4        Test for Zero or Minus
00000090  BREQ PC+0x36        Branch if equal
00000091  DEC R4        Decrement
...
        if (counter3-- == 0) {counter3 = 126; fbi(PORTB, 0);}
000000C4  CPSE R4,R1        Compare, skip if equal
000000C5  RJMP PC-0x0034        Relative jump
000000C6  LDI R26,0x7E        Load immediate
000000C7  MOV R4,R26        Copy register
000000C8  IN R25,0x05        In from I/O location
000000C9  EOR R25,R24        Exclusive OR
000000CA  OUT 0x05,R25        Out to I/O location
 
That is very interesting. Looks like it spread them apart to minimize jumps and even duplicated some parts of the code. That's a very good job!!! Frankly, I wouldn't expect it to do such things. I'm impressed.

Surprisingly, it missed easy stuff in --x case, but did it in the x--. For example:

Code:
00000093 BRNE PC+0x02 Branch if not equal
00000094 RJMP PC+0x0046 Relative jump

This is equivalent to one BREQ command. And in the x-- case it did just that:

Code:
00000090 BREQ PC+0x36 Branch if equal

Or here, it uses temprary register R25 instead of working directly with R4:

Code:
00000091 MOV R25,R4 Copy register
...
00000095 MOV R4,R25 Copy register

but not in the x-- case:

Code:
0000008F TST R4 Test for Zero or Minus
...
00000091 DEC R4 Decrement

Could that be different optimization settings? Is that the highest level of optimization in both cases?

It did miss some obvious things in both cases:

Code:
000000C6 LDI R26,0x7E Load immediate
000000C7 MOV R4,R26 Copy register

You can replace this with

Code:
LDI R4,0x7E

But this is in the "slow" part of the code, so it doesn't matter much in this case.
 
What is the meaning of those "--" as in here --counter3 == 0?

I seem to recall something like "++"...

Non conversant in C.
 
What is the meaning of those "--" as in here --counter3 == 0?

I seem to recall something like "++"...

Non conversant in C.

Those are increment and decrement operations.

x++;
is same as
x = x+1;

Now, if you do some other operations in the same "sentence", like comparison:
x++ == 0
that means "first compare and then add one to x". This is called post increment.

++x == 0
means "first add one to x, then compare". This is called pre increment.

Same thing with minus signs, but that is decrement by one, of course.
So,
--counter3 == 0
means "first subtract one from counter3 and then compare (against zero)".
 
Last edited:
It did miss some obvious things in both cases:

Code:
000000C6 LDI R26,0x7E Load immediate
000000C7 MOV R4,R26 Copy register

You can replace this with

Code:
LDI R4,0x7E

But this is in the "slow" part of the code, so it doesn't matter much in this case.

I think the value "0x7e" is loaded into r26 only once and then re-used from there whenever the r4 reaches zero.
I don't remember much what exactly was going on with this code. Sorry for not responding to your post back then.

edit: well, the jumps go to the ldi instruction. That is thread safety, I think. But true, the value could be loaded straight into r4. The compiler has some rules how it uses registers that the programmer can trust.. in case he wants to do some inline-assembly or some other fancy stuff. So I think that the rules do not allow the compiler to "ldi" straight into register r4.
 
Last edited:
Those are increment and decrement operations.

x++;
is same as
x = x+1;

Now, if you do some other operations in the same "sentence", like comparison:
x++ == 0
that means "first compare and then add one to x". This is called post increment.

++x == 0
means "first add one to x, then compare". This is called pre increment.

Same thing with minus signs, but that is decrement by one, of course.
So,
--counter3 == 0
means "first subtract one from counter3 and then compare (against zero)".

Gracias misterT! It makes sense to me now.

My stumbling block when learning C where pointers. :banghead: I left right there and never tried again.
 
pitch 36 is 207.652
pitch 37 is 220.000
pitch 38 is 233.082
pitch 39 is 246.942
pitch 40 is 261.626
pitch 41 is 277.183
pitch 42 is 293.665
pitch 43 is 311.127
pitch 44 is 329.628
pitch 45 is 349.228
pitch 46 is 369.994
pitch 47 is 391.995

Hola Wip

I am not sure so I have to ask you:

a) have you found the way to output the 12 outputs simultaneously, that is, each one through one of 12 pins?
b) are you actually generating the frequencies in the list above?
c) Why 432 and not 440? Could have been 434 or 438 as well?
d) Are you going to post a detailed explanation of how the strings are plucked?

Gracias
 
a) have you found the way to output the 12 outputs simultaneously, that is, each one through one of 12 pins?

Yes I can output 12 PWM simultaneously using "normal" digital pins. I ended up using the C code of NorthGuy.

b) are you actually generating the frequencies in the list above?

Yes, but because I am also using VUSB the cpu is quite busy, so the precision of the PWM / timer is not as great as I wanted (in the higher frequencies).

c) Why 432 and not 440? Could have been 434 or 438 as well?

There's a lot of stuff going on for 432hz vs 440hz. Like stated on my site: "The tuning is in 432hz, because I’d rather be in tune using universal number than universal standardization." But yes could be anything.

d) Are you going to post a detailed explanation of how the strings are plucked?

The strings are not plucked, but they vibrate because of the magnetic field produce by the coils.
 
Yes, but because I am also using VUSB the cpu is quite busy, so the precision of the PWM / timer is not as great as I wanted (in the higher frequencies).

I can suggest a slight improvement. Perhaps it can make it run faster.

Instead of this:

C:
for (i = 0; i <12; i++) {
   if (z&mask) {
     if(i > 7) {
       PORTE ^= (1 << (i - 8));
     } else {
       PORTB ^= (1 << i);
     }
     x[(p+f[i])&MASK] |= mask;
   }
   mask <<= 1;
}

I would suggest this:

C:
PORTE ^= z >> 8;
PORTB ^= z; // assumes 8-bit CPU
 
for (i = 0; i <12; i++) {
   if (z&mask) {
     x[(p+f[i])&MASK] |= mask;
   }
   mask <<= 1;
}
 
The strings are not plucked, but they vibrate because of the magnetic field produce by the coils.

Gracias for replying Wip.

Sorry to insist: will you show details on how to make them vibrate? I am really interested.
Thanks again.
 
Also, can you post here when you make the videos and sound examples? I have your page open in a tab, but I doubt I will keep checking it. Still Id love to see the real outcome.
 
Hi,

Here's a quick video that I just did. Lower your volume and hide your cat:

As you can hear there's a lot of USB noise in the output. It might be also noise coming from the capacitive scan (using the ADC of my Atmega). I am not even sure where to begin troubleshooting the noise and if it is possible at all :(
 
Looks like the frequencies are not very precise - there's a lot of noise in few Hz - may be because timer interrupts are lost or delayed. This cannot be an effect of low precision. Desite of low precision, it still should produce stable frequency. But this may also be an effect of interference between strings - sort of like playing on un-tuned guitar.

About the USB noise - you need to give priority to the PWM generation compare to USB.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top