Music library brainstorm


(Scott) #12

With regards to my previous suggestion to use pins 6 and 13, can’t you generate two different sounds using OC4D and OC4A?


#13

Yes, but you do not get the option to have a complementary output for free. (I agree that 5/13 or 6/13 is more or less equal.)


(Scott) #14

It’s a trade off. With 6/13 you need to do a small amount of extra work to set up complimentary (increased volume) output but you don’t have the hassle of handling normal use of pins 5 and/or 12.

I guess we need to determine for sure if it’s possible to have a complimentary PWM output on a pin while still being able to use the pin dedicated to the normal phase as a general purpose output. I used section 15.12.3 TCCR4C – Timer/Counter4 Control Register C in the ATmega32U4 datasheet as a reference.


#15

No, to my reading of the datasheet and to @stg’s reading, that is not possible. That is the problem of pin 12.

Regarding pins 5/13 and 6/13, I do not know if it is better to use OC3A/OC4A or OC4D/OC4A to mix two sounds. I think @ChrisS had some opinion on this.


(Scott) #16

Well, I’d say we need to decide which is better quite quickly, since it looks like if we try to do PWM on the current speaker pins 5 and/or 12, it will cause problems with display DC (Pin 13) and RST (Pin 6).

Hopefully we can decide in time so that @bateske can make changes before the hardware design is locked down.


(Chris Smith) #17

If you are mixing two independent sounds, the lock-in or phasing of the underlying timers should not matter. This is entirely in the audio domain.

If you are trying for volume amplification, with matching but complementary outputs, then you need the phase matching. With various harmonics are differing frequencies, and therefore at differing phase relationships, you might only get volume amplification on some frequencies, while getting cancellation on some of the harmonics. It might actually sound quite cool - I know people who play with exactly those features - but they do that precisely because it is unpredictable. “Unpredictable” is usually not a desirable feature when you’re aiming for amplification.

As to the ability to keep the complementary outputs without the original - let’s just say, that is one really complex section of datasheet!

First …

10.3.3 Alternate Functions of Port D, • T1/OC.4D/ADC9 – Port D, Bit 6

OC.4D: Timer 4 Output Compare D. This pin can be used to generate a high-speed PWM signal from Timer 4 module, complementary to OC.4D (PD7) signal. The pin has to be configured as an output (DDD6 set “one”) to serve this function.

I don’t think there is any doubt on this point - if the complementary signal is generated, we can route it out this pin.

On to 15.12.3 TCCR4C – Timer/Counter4 Control Register C, particularly • Bits 3,2 - COM4D1, COM4D0: Comparator D Output Mode, Bits 1 and 0.

The sentence that would give me doubt is “The complementary OC4D output is connected only in PWM modes when the COM4D1:0 bits are set to “01”.

So - when do we set 01? My reading of tables 15-15, 15-16, 15-17 is that in Normal (Non-PWM) mode (Table 15-15) we do indeed lose the complementary output. (This would seem to contradict the sentence above.) But in Table 15-16. Compare Output Mode, Fast PWM Mode and Table 15-17. Compare Output Mode, Phase and Frequency Correct PWM Mode, I note that when setting 01 (which has different meanings in the two tables), the complementary output is listed as connected, but disconnected in all of the other three modes.

Finally, the block diagram for the timer/PWM section strongly suggests that the ‘connected’ and ‘disconnected’ applies inside the block. This would seem to indicate that, as long as the signal is ‘connected’ in the PWM block, it is available for the alternate function of the pin.

So - it’s back to the libraries. Is the 01 mode in either Fast PWM Mode or the Phase and Frequency Correct PWM Mode the setting that is used in the libraries? I would have to hand that question back to someone extremely familiar with those libraries. If the libraries use different modes, then we lose the complementary output. If they do use the 01 mode, then it appears we keep the complementary output.


I’ve tried to be almost excessively complete, so that if I am wrong, it’s far easier for someone to point out where my logic chain broke.


(Kevin) #18

Hey guys I found this project that is only using one pin to generate 4 voices 5 notes polyphony:


http://wiki.openmusiclabs.com/wiki/MixtapeAlpha

Soooo… pins 6 and 13? is where we are at now? Awesome work guys I can barely keep along with your knowledge of timers!


#19

to be clear: we can do 4 voices with one pin. The suggestion of 2 pins came, when there was the idea of amplification or effects. And actually it came independent of the 4 voices tracker idea. All existing libraries that do 4 voice music use 1 pin.

2 pins give more options, if chosen correctly.


Arduboy Kickstarter version design discussion
(Scott) #20

But in all “01” modes where _OC4D is given as connected, the non-inverted OC4D (Port D Bit 7, Arduino Pin 6) is also shown as connected. So as far as I read it, if Pin 6 is set as an output it will always be the compliment of _OCD4 on Pin 12.

This means if we want to use Pin 6 for display RST, we will have to use the trick I mentioned of setting it to an input until we want to do a reset (and for this we may also need an external pull-up). The same goes for OC4A on Pin 13 if we try to use _OC4A on Pin 5. I don’t think it would be wise to try to use this “idle as an input” trick with display CS or DC.

Whether we need an external pull-up depends on if the internal pull-up becomes disabled every time the OC4x signal goes low. This would be pretty easy to test.

Assuming we can’t prevent an output pin on OC4x from toggling when complimentary _OC4x toggles in mode “01”, then I think it’s best to use one of the following:

  • Speaker on pins 6/13:
    • Uses OC4D and OC4A for separate sounds.
    • For increased volume OC4D and OC4A are programmed individually to generate synchronized complimentary signals.
    • No problems with using Pin 5 (_OC4A) and Pin 12 (_OC4D) as general purpose outputs for the display.
  • Speaker on pins 5/13:
    • Uses OC3A and OC4A for separate sounds.
    • For increased volume OC4A and _OC4A can be easily used.
    • No problems with using Pin 6 (OC4D) and Pin 12 (_OC4D) as general purpose outputs for the display.

So it’s back to the question: Is it better to use OC3A or OC4D to generate PWM sounds separate from PWM sounds generated with OC4A? If it’s a toss up, we should consider if leaving Timer 3 unused might make it more useful for other non sound related purposes.


(Scott) #21

Given that this is the case; that we would likely only use PWM on one pin, with the second pin only being used for simple non-PWM tones and effects (and perhaps muting and lowering the volume), then maybe 5/13 is the best way to go. OC3A, though available, would be left alone, to leave Timer 3 available for other purposes. OC4A (Pin 13) would be used alone for regular volume and _OC4A (on Pin 5) would be enabled for higher volume.


(Chris Smith) #22

Ah, I can see that interpretation.

I would disagree, with the following evidence. Go take a look at section 15.5 Dead Time Generator. Now dead time is really only needed for certain power applications, and we don’t need it here for audio purposes. But a key point of this section is that OCxn and _OCxn are not always exact complements of each other. The dead-time generator takes the PWM output, and generates both the postive and negative versions based on dead-time configurations.

But that’s key – both are generated and available at the outputs of the dead-time module. And it must be this way, because the two signals might not be exact opposites. Pin 6 is not the complement of Pin 12 - Pin 6 is OC4D, and Pin 12 is _OC4D, as determined by the PWM module, including the dead-time module.


(Kevin) #23

Coming in on 5/13 looks like? What could we do to test this?


#24

In the Arduino library:

  • analogWrite() sets COM4A1…0 and COM4D1…0 to “10” and sets the mode to phase- and frequency-correct PWM (see wiring_analog.c and wiring.c)
  • digitalWrite() sets COM4A1 and COM4D1 to “0” (see wiring_digital.c)

This means that doing analogWrite(6, chocolate) or digitalWrite(6, potato_salad) would disable the complementary output on pin 12, as we had predicted.


#25

Here is the test for the OC4A and _OC4A (“complementary mode”):

// Generate a super sawtooth on pins 5+13 using ISR+PWM on Timer 4A

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup() {
  // Enable buzzer output pins
  pinMode(5, OUTPUT);
  pinMode(13, OUTPUT);

  // Set Timer 4 prescale factor to 1 (CS43..1 = 0001)
  cbi(TCCR4B, CS43);
  cbi(TCCR4B, CS42);
  cbi(TCCR4B, CS41);
  sbi(TCCR4B, CS40);

  // Put timer 4 in phase- and frequency-correct PWM mode (PWM4x = 1 and WGM40 = 1)
  sbi(TCCR4A, PWM4A);
  sbi(TCCR4D, WGM40);

  // Connect PWM on Timer 4 to channels OC4A and _OC4A (COM4x1..0 = 01)
  cbi(TCCR4A, COM4A1);
  sbi(TCCR4A, COM4A0);

  // Enable timer 4 overflow interrupt
  sbi(TIMSK4, TOIE4);

  // Clear interrupt just to be sure
  sbi(TIFR4, TOV4);
}

void loop() {
}

// Timer 4 overflow interrupt
byte divider;
word f1, f2, f3, f4;
ISR(TIMER4_OVF_vect) {
  // Sample rate 1:3 prescaler
  if (++divider < 3) return;
  divider = 0;

  // Quick non fractional sawtooths
  f1 += 3328;
  f2 += 3338;
  f3 += 3348;
  f4 += 3358;

  // Mix and output using PWM
  OCR4A = (byte)(f1 >> 10)
          + (byte)(f2 >> 10)
          + (byte)(f3 >> 10)
          + (byte)(f4 >> 10);
}

And here is the test for OC4A and OC3A (“two timers mode”):

// Generate a super sawtooth on pins 5+13 using ISR+PWM on Timer 3A+4A

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup() {
  // Enable buzzer output pins
  pinMode(5, OUTPUT);
  pinMode(13, OUTPUT);

  // Set Timer 3 prescale factor to 1 (CSn2..1 = 001)
  cbi(TCCR3B, CS32);
  cbi(TCCR3B, CS31);
  sbi(TCCR3B, CS30);

  // Put timer 3 in 8-bit phase correct pwm mode (WGM30 = 1)
  sbi(TCCR3A, WGM30);

  // Set Timer 4 prescale factor to 1 (CS43..1 = 0001)
  cbi(TCCR4B, CS43);
  cbi(TCCR4B, CS42);
  cbi(TCCR4B, CS41);
  sbi(TCCR4B, CS40);

  // Put timer 4 in phase- and frequency-correct PWM mode (PWM4x = 1 and WGM40 = 1)
  sbi(TCCR4A, PWM4A);
  sbi(TCCR4D, WGM40);

  // Connect PWM on Timer 3 to channel OC3A (COM3x1 = 1)
  sbi(TCCR3A, COM3A1);

  // Connect PWM on Timer 4 to channel OC4A (COM4x1..0 = 10)
  sbi(TCCR4A, COM4A1);
  cbi(TCCR4A, COM4A0);

  // Enable timer 4 overflow interrupt
  sbi(TIMSK4, TOIE4);

  // Clear interrupt just to be sure
  sbi(TIFR4, TOV4);
}

void loop() {
}

// Timer 4 overflow interrupt
byte divider;
word f1, f2, f3, f4;
ISR(TIMER4_OVF_vect) {
  // Sample rate 1:3 prescaler
  if (++divider < 3) return;
  divider = 0;

  // Quick non fractional sawtooths
  f1 += 3328;
  f2 += 3338;
  f3 += 3348;
  f4 += 3358;

  // Mix and output using PWM
  OCR3A = (byte)(f1 >> 10)
          + (byte)(f2 >> 10);
  OCR4A = 255 - (byte)(f3 >> 10)
          - (byte)(f4 >> 10);
}

I have used phase- and frequency-correct PWM this time as I think it is more logical for sound.

The output works well in both tests and they both sound fine!

The second test is quieter so there may be some frequencies canceling each other. Intuitively, I advise to use the complementary mode for the ATM library even if I cannot explain it rationally.


(Scott) #26

I guess an actual test could sort this out one way or the other. Regardless, is there any problem with using pins 5/13 or 6/13? Either pin pair would make this issue moot.

Good to know, but does it matter? I would assume that an Arduboy specific audio library (the subject of this thread) would be the preferred method of using the speaker for PWM, and possibly for simple tones and other sound generation methods as well. This way, mixing, volume and other features would be easy for developers to implement. There probably wouldn’t be a problem with using analogWrite(), digitalWrite(), or even tone() but I think an Arduboy library should be available and its use encouraged.


(Scott) #27

So are you leaning towards recommending pins 5/13, as I’ve most recently suggested and you previously have as well?

Does anyone else have an opinion?


#28

This is what stg said on IRC:

I’ve recommended OC4A and !OC4A. I stand by this, and I’ve given my reasons. Someone will need to make a choice.

This means using pins 5/13 for audio.

@davidperrenoud is with me on this too.


(Scott) #29

So, of the people who have been discussing this, it looks like myself (@MLXXXp), @davidperrenoud and @JO3RI (and also non-member @stg) are all in favour of using Arduino Pin 5 (PC6, OC3A & _OC4A) and Pin 13 (PC7, OC4A) for the speaker.

Unless @ChrisS has an objection to this, I’d say 5/13 is what we recommend (instead of the previous 5/12).

If @bateske agrees to this, and makes any changes necessary to implement it, then the discussion in this thread can return to its original topic intent, and these pins can be assumed for software design and experimentation.


(Chris Smith) #30

I have no objection.

We are, I think, deep in “last 2%” territory here. Any further potential improvements will consume time and discussion resources out of proportion to the value of results - which are themselves uncertain, because they will only really crystalize when thousands of devices start getting used for development.

5/13 certainly delivers lots of capability, and fully utilizing it in a game or demo would make the Arduboy deliver beyond expectations.

Go 5/13!


#31

See [WIP] 4 channel Music