# 12 simultaneous & unique frequencies (PWM)

Discussion in 'AVR' started by wip, Mar 20, 2014.

1. ### misterTWell-Known MemberMost Helpful Member

Joined:
Apr 19, 2010
Messages:
2,697
Likes:
368
Location:
Finland
This is after the decrements.

Code (ASM):

if (counter1 == 0) {counter1 = 112; fbi(PORTB, 0);}
00000097  CPSE R2,R1        Compare, skip if equal
00000098  RJMP PC+0x0006        Relative jump
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

2. ### misterTWell-Known MemberMost Helpful Member

Joined:
Apr 19, 2010
Messages:
2,697
Likes:
368
Location:
Finland
I modified to code to:

Code (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: Mar 23, 2014
3. ### NorthGuyWell-Known Member

Joined:
Sep 8, 2013
Messages:
1,218
Likes:
206
Location:
I think you need:

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

Joined:
Jan 12, 1997
Messages:
-
Likes:
0

5. ### misterTWell-Known MemberMost Helpful Member

Joined:
Apr 19, 2010
Messages:
2,697
Likes:
368
Location:
Finland

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.

6. ### NorthGuyWell-Known Member

Joined:
Sep 8, 2013
Messages:
1,218
Likes:
206
Location:
That is strange. Could you post a disassemby?

7. ### misterTWell-Known MemberMost Helpful Member

Joined:
Apr 19, 2010
Messages:
2,697
Likes:
368
Location:
Finland
if (--counter3 == 0) {counter3 = 126; fbi(PORTB, 0);}
Code (ASM):

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
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 (ASM):

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

8. ### NorthGuyWell-Known Member

Joined:
Sep 8, 2013
Messages:
1,218
Likes:
206
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 (ASM):
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 (ASM):
00000090 BREQ PC+0x36 Branch if equal
Or here, it uses temprary register R25 instead of working directly with R4:

Code (ASM):
00000091 MOV R25,R4 Copy register
...
00000095 MOV R4,R25 Copy register
but not in the x-- case:

Code (ASM):
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 (ASM):
000000C7 MOV R4,R26 Copy register
You can replace this with

Code (ASM):
LDI R4,0x7E
But this is in the "slow" part of the code, so it doesn't matter much in this case.

9. ### wipMember

Joined:
Nov 20, 2013
Messages:
38
Likes:
2
Location:
NorthGuy, MisterT and all who helped me: THANK YOU !!!

Here's the project I was working on:
Phibow aka 432 de Coulombe
(I will post audio / video soon; code source is there)

Cheers!

10. ### atferrariWell-Known Member

Joined:
Oct 8, 2003
Messages:
2,812
Likes:
121
Location:
Buenos Aires - Argentina
ONLINE
What is the meaning of those "--" as in here --counter3 == 0?

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

Non conversant in C.

11. ### NorthGuyWell-Known Member

Joined:
Sep 8, 2013
Messages:
1,218
Likes:
206
Location:
You're welcome!

You have built an amazing thing. Congratulations. I'm glad you used our code.

12. ### misterTWell-Known MemberMost Helpful Member

Joined:
Apr 19, 2010
Messages:
2,697
Likes:
368
Location:
Finland
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: Jul 23, 2014
13. ### misterTWell-Known MemberMost Helpful Member

Joined:
Apr 19, 2010
Messages:
2,697
Likes:
368
Location:
Finland
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: Jul 24, 2014
14. ### atferrariWell-Known Member

Joined:
Oct 8, 2003
Messages:
2,812
Likes:
121
Location:
Buenos Aires - Argentina
ONLINE
Gracias misterT! It makes sense to me now.

My stumbling block when learning C where pointers. I left right there and never tried again.

15. ### atferrariWell-Known Member

Joined:
Oct 8, 2003
Messages:
2,812
Likes:
121
Location:
Buenos Aires - Argentina
ONLINE
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

16. ### wipMember

Joined:
Nov 20, 2013
Messages:
38
Likes:
2
Location:
Yes I can output 12 PWM simultaneously using "normal" digital pins. I ended up using the C code of NorthGuy.

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

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.

The strings are not plucked, but they vibrate because of the magnetic field produce by the coils.

17. ### NorthGuyWell-Known Member

Joined:
Sep 8, 2013
Messages:
1,218
Likes:
206
Location:
I can suggest a slight improvement. Perhaps it can make it run faster.

Code (C):
for (i = 0; i <12; i++) {
if(i > 7) {
PORTE ^= (1 << (i - 8));
} else {
PORTB ^= (1 << i);
}
}
}
I would suggest this:

Code (C):
PORTE ^= z >> 8;
PORTB ^= z; // assumes 8-bit CPU

for (i = 0; i <12; i++) {
}
}

18. ### atferrariWell-Known Member

Joined:
Oct 8, 2003
Messages:
2,812
Likes:
121
Location:
Buenos Aires - Argentina
ONLINE

Sorry to insist: will you show details on how to make them vibrate? I am really interested.
Thanks again.

19. ### kubeekWell-Known Member

Joined:
Mar 11, 2006
Messages:
1,487
Likes:
186
Location:
Prague, Czechia (not Chechnya)
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.

20. ### wipMember

Joined:
Nov 20, 2013
Messages:
38
Likes:
2
Location:
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

Joined:
Sep 8, 2013
Messages:
1,218
Likes:
206
Location: