• Busy Bee mini synthesizer demo

    Jacques01/07/2018 at 15:23 0 comments

    Sure one can do it with a 555 TIMER but it would require more components. With an MCU like the EFM8BB10F8G there is no need for resistors and capacitors for frequencies determination. All tones are derived from the internal high frequency oscillator. The Busy Bee as plenty of  timers to divide oscillator frequency. For this project I use the Programmable Counter Array with channel 0 comparator.

    Hardware

    The 12 keys are connected to digitals inputs using 3 ports. P2.0, P0.1-P0.7 and P1.0-P1.3. No need for debouncing so the reading of switch is quite simple. The audio output is from P0.0 pin with a small 1 inch, 150 ohm speaker connected between +3volt and the pin.

    As the circuit draw 11.54Ma  when sounding a more capable CR2450 button cell is used. When Idle the circuit draw 1.87Ma.

    I didn't have any SOIC-16 breakout board so I glued the MCU to protoboard with hot glue and did some wire patching using 30AWG solid wire. I had white and black tact switches so I decided to arrange like a panio where the sharp tones are black. The keyboard goes from C5 to B5

    Software

    Once the project is created in Simplicity Studio the first step is in configurator.

    The MCU is driven by the High-Frequency Oscillator divided by 4, giving 6.125Mhz for SYSCLK signal.

    The watchdog timer is disabled as not required.

    We need to enable interrupts on PCA0 peripheral.

    We enable the crossbar and the internals pull-ups for digitals inputs. This way external pull-ups resistors won't be required.

    All pins are skipped by the crossbar and configured as Digital OpenDrain I/O.

    The PCA0 is enabled using SYSCLK/12 as counter pulse. This give a counter frequency of 510.417Khz.

    The Channel 0 of PCA0 is configured as software timer and the Capture/Compare Flag Interrupt is Enabled.  This way each time the PCA0 counter will equal channel 0 comparator value an interrupt will be triggered.


    We are done in the configurator.

    Few code required


    In the interrupt routine all we have to do is to toggle the audio output pin P0.0 and increment the comparator value by the step required to produce the desired tone frequency.  Step value is :

    Sval=Fpca/2/Ftone

    for C5 which is 523 hertz that give:

    Sval=510,417/2/523=488   (rounded to nearest integer). Fpca is divided by  2 because the pin must be toggled 2 times per audio cycle. The interrupt rate is 2 times the audio frequency.

    unsigned int step;
    SI_INTERRUPT (PCA0_ISR, PCA0_IRQn)
    {
        if (PCA0CN0&PCA0CN0_CCF0__BMASK){
            PCA0CN0&=~(PCA0CN0_CCF0__BMASK);
            if (step){
              P0_B0^=1;
              PCA0CP0+=step;
            }
        }
    }
    

    The 12 values for tempered scale have been pre-computed and stored in program memory as a table, which is in BBsynth2_main.c file.

    code unsigned int scale[12]={
    488,  //C5 523 Hertz
    460,  //Cs5
    435, // D5
    410, //Ds5
    387, //E5
    365, // F5
    345, // Fs5
    326, // G5
    307, // Gs5
    290, //A5 880 Hertz
    274, //As5
    258,  //B5
    };
    

    In the main()  function all there is to do is to read the key switches in loop and each time a key is pressed step variable is adjusted for the frequency corresponding to that key. The for loop  exit at first key down met in scan order. If more than one key is down the first in scan order is sounded and the next is ignored. If no key is down step is set to 0 and ouput pin is set to high to avoid DC current drain from speaker.

    int main (void)
    {
        unsigned int i,keys;
      // Call hardware initialization routine
      enter_DefaultMode_from_RESET();
      step=0;
      while (1) 
      {
        // $[Generated Run-time code]
        // [Generated Run-time code]$
        keys=(P2&1)+(P0&0xfe)+((P1&0xf)<<8);
    //    if (!P2_B0) step=scale[0];
    //    else if (!P0_B1)step=scale[1];
    //    else step=0;
        for (i=0;i<12;i++){
            if (!(keys&(1<<i))){
                step=scale[i];
                break;
            }//if
        }//for
        if (i==12){
            step=0;
            P0_B0=1;
        }//if
      }//while
    }//main()
    

     This is...

    Read more »