1. 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.
    Dismiss Notice

12 simultaneous & unique frequencies (PWM)

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

  1. misterT

    misterT Well-Known Member Most 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
    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
     
     
  2. misterT

    misterT Well-Known Member Most 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. NorthGuy

    NorthGuy Well-Known Member

    Joined:
    Sep 8, 2013
    Messages:
    1,218
    Likes:
    206
    Location:
    Northern Canada
    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.
     
  4. dave

    Dave New Member

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


     
  5. misterT

    misterT Well-Known Member Most 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. NorthGuy

    NorthGuy Well-Known Member

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

    misterT Well-Known Member Most 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
    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 (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
    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
     
     
  8. NorthGuy

    NorthGuy Well-Known Member

    Joined:
    Sep 8, 2013
    Messages:
    1,218
    Likes:
    206
    Location:
    Northern Canada
    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):
    000000C6 LDI R26,0x7E Load immediate
    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. wip

    wip Member

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

    atferrari Well-Known Member

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

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

    Non conversant in C.
     
  11. NorthGuy

    NorthGuy Well-Known Member

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

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

    misterT Well-Known Member Most 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. misterT

    misterT Well-Known Member Most 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. atferrari

    atferrari Well-Known Member

    Joined:
    Oct 8, 2003
    Messages:
    2,816
    Likes:
    121
    Location:
    Buenos Aires - Argentina
    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.
     
  15. atferrari

    atferrari Well-Known Member

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

    wip Member

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

    NorthGuy Well-Known Member

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

    Instead of this:

    Code (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:

    Code (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;
    }
     
  18. atferrari

    atferrari Well-Known Member

    Joined:
    Oct 8, 2003
    Messages:
    2,816
    Likes:
    121
    Location:
    Buenos Aires - Argentina
    Gracias for replying Wip.

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

    kubeek Well-Known Member

    Joined:
    Mar 11, 2006
    Messages:
    1,510
    Likes:
    189
    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. wip

    wip Member

    Joined:
    Nov 20, 2013
    Messages:
    38
    Likes:
    2
    Location:
    Montreal, Canada
    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 :(
     
  21. NorthGuy

    NorthGuy Well-Known Member

    Joined:
    Sep 8, 2013
    Messages:
    1,218
    Likes:
    206
    Location:
    Northern Canada
    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.
     

Share This Page