Noisey chips

Preamble

Following on from Banging noises…, I attempted to recreate the Noise Chip (U4) depicted in the LDB-1 schematic, from the article Anatomy of a drum machine. The noise chip creates both a white noise signal as well as four tuned square waves at different (unknown) frequencies. I have attempted to contact the author for more details but have not had a reply as yet.

It is using either PIC (which is likely seeing as the author states a preference for the PIC microcontrollers), or an ATtiny.  I will attempt to use a ATtiny/ATmega microcontroller (specifically ATmega48P/88P/168P/328P but the code should compile for most Arduinos).

Note that parts of this are a work in progress.

Note: The phase-correct 50% trick is possible with Timer0 on an ATtiny85, but it is not clear if it is possible with Timer1 (although Timer0 does have two channels). Atmel AVR ATtiny comparison chart

See also

Links

Very informative AVR tutorials

Stack exchange related links

DR-110 Links

Notes

  1. We need a ATtiny that has 5 outputs, so that discounts the ATtiny13, ATtiny15 – Is this true? They have five outputs, two of which are PWM.
  2. The square wave frequencies are probably not much higher than 100 kHz, so a 1 MHz internal clock is probably sufficient – unless precise frequencies are required (which they probably are, to maintain a quality of note – although no notes are produced, just percussion, so maybe not so important after all.

What is being reproduced?

The noise chip IC, U4, in the LDB-1 schematic is undocumented:

Noisechip (U4)
Noisechip (U4)

This schematic was the original physical circuit which the Noise Chip (U4) replaces

Boss DR-110 cymbal & noise circuits
Boss DR-110 cymbal & noise circuits

The article states that four tuned square waves are produced (at points 1-4 indicated in the above schematic). No more information other than that. Frequency could be calculated from the values of the resistors and capacitors. However, the value of the capacitors is not shown.

The white noise is produced by a 16 bit LFSR. In hardware versions, the CD4006 (18 stage register) and a CD4070 XOR are used (see LFSR).

Further reading

After a bit of a search, I found this excellent article, An analysis of the DR-110 Cymbal, Hi-Hat and Clap, with suggested modifications and proposed clones that has a slightly different schematic

Boss DR-110 cymbal & noise circuits - second schematic
Boss DR-110 cymbal & noise circuits – second schematic

It also, thankfully, has a table from the original DR-110 documentation:

DR-110 waveforms
DR-110 waveforms

The four frequencies are:

  • 1.15 kHz
  • 820 Hz
  • 317 Hz
  • 465 Hz

At the very end of that article (it runs for three pages), there is even an image of the noise chip, which is a PIC (and is available for purchase), with the respective frequencies!

Noise chip (U4) with frequencies
Noise chip (U4) with frequencies

From Boss DR-110 and C Y, the full schematic of the Voicing board,

Boss DR-110 Voicing Board schematic
Boss DR-110 Voicing Board schematic

Sources

White noise

This white noise, assembler code for ATtiny13 and ATtiny15, Noise Generator with ATTiny15.

Other sources were used, as can be seen at the end of the article.

Square waves

from Program an ATTiny13 as an audio oscillator with variable frequency and pulse-width

Note:  The choice of 0b100 for WGM0[2,1,0] won’t set CTC mode. (In fact it’ll set a mode that’s reserved by Atmel.) The ATtiny13 datasheet says CTC mode needs value 2; you’ve accidentally given it _bit_number_ 2 instead (i.e. value 4). Because of that it’s also necessary not only to change (i.e. clear) WGM02 in TCCR0B but also to set bits WGM01 and WGM00 to 1 and 0 respectively. Those bits are in TCCR0A, so it’s not sufficient to set TCCR0A with only the COM0A bits.

Attempt#1 – Using CTC hardware

The main setup code from Newbie’s Guide to AVR Timers – Part Six – Pure Hardware CTC. Uses bit 5 of port D, pin D5 (Digital pin 5)

#include 
#include 

int main (void)
{
   DDRD |= (1 << 5); // Set LED as output
   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
   TCCR1A |= (1 << COM1A0); // Enable timer 1 Compare Output channel A in toggle mode
   OCR1A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
   TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
   for (;;)
   {

   }
}

The Interrupt Service routine, from Newbie’s Guide to AVR Timers – Part Five – CTC Mode using Interrupts:

ISR (TIMER1_COMPA_vect)
{
 PORTB ^= (1 << 0); // Toggle the output
}

Note: The ISR routine is not required for the hardware only version above.

Using the #include lines from ATtiny85: Introduction to Pin Change and Timer Interrupts

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

Putting it together gives

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

int main (void) {
  DDRD |= (1 << 5); // Set digital pin 5 as output
  TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
  TCCR1A |= (1 << COM1A0); // Enable timer 1 Compare Output channel A in toggle mode
  OCR1A = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
  TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
  for (;;) { }
 } 

ISR (TIMER1_COMPA_vect) {
  PORTB ^= (1 << 0); // Toggle the output
}

This compiles. But is it correct?

NOTE: As already stated, the ISR routine is not required for the hardware only version above.

More outputs

The Compare output ports are

PB3 = OC0
PD4 = OC1B
PD5 = OC1A

See Port Registers for port to pin mappings;

The chips used on the Arduino board (the ATmega8 and ATmega168) have three ports:

  • B (digital pin 8 to 13)
  • C (analog input pins)
  • D (digital pins 0 to 7)

Each port is controlled by three registers, which are also defined variables in the Arduino language. The DDR register, determines whether the pin is an INPUT or OUTPUT. The PORT register controls whether the pin is HIGH or LOW, and the PIN register reads the state of INPUT pins set to input with pinMode().

To add extra timers, need to enable more outputs. Currently we have

DDRD |= (1 << 5); // Set digital pin 5 as output

so we add

DDRD |= (1 << 4); // Set digital pin 4 as output

However, it is not clear, yet unlikely that timer1 can handle two different frequencies (i.e. to different compare values), so we could just enable both and use the second output through a divide by two circuit (using a D type flip-flop).

So presumably we just add

 TCCR1A |= (1 << COM1B0); // Enable timer 1 Compare Output channel B in toggle mode

I am not sure if that works correctly, as expected, with both outputs (digital pin 4 and 5 toggling).

Note

From Configuring Timer1 for OCR1A and OCR1B interrupts

  1. It is NOT possible to use two different compare values for A and B on Timer1, as the timer resets when it encounters the lower value compare – thus the higher compare value is never reached.
  2. Just use one Timer and the rest in software:

Generally, that is what most would do — have one base timer tick and accumulate into “soft timers” for other intervals.

However, this thread, Two timers, three frequencies–ideas? suggests that two different values, on Timer2 are possible.

From Secrets of Arduino PWM – Using the ATmega PWM registers directly. Actually use Ken Schirriff’s original page, as the Arduino page is ridiculously buggy as next to totally useless

The two outputs for each timer will normally have the same frequency, but can have different duty cycles (depending on the respective output compare register).

It is not clear if this applies to the CTC counters though. It may only apply to PWM timers. I haven’t fully understood, and will revisit later.

NOTE: I have given up using this method for the moment as it is not clear if enough different frequencies are possible, without using soft timers. It maybe that only three frequencies are possible using this hardware method.

Attempt #2 – Using PWM timers

From Secrets of Arduino PWM – Varying the timer top limit: fast PWM and Varying the timer top limit: phase-correct PWM, it seems relatively easy to get two square waves with different frequencies (albeit with 50% difference).

Fast PWM Mode with OCRA top

Using fast PWM Mode with OCRA top.

Where

  • We are using Timer2 and the associated pins 3 and 11
  • The waveform generation mode bits WGM are set to to 111 for fast PWM with OCRA controlling the top limit
int main() {
   pinMode(3, OUTPUT);    // Set as output
   pinMode(11, OUTPUT);   // Set as output
   TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
   TCCR2B = _BV(WGM22) | _BV(CS22);  // prescale 64
   OCR2A = 180;     // top limit
   OCR2B = 50;      //arbitrary duty cycle for output B (output A is fixed at 50%)
}

Giving

  • Output A frequency: 16 MHz / 64 / (180+1) / 2 = 690.6Hz
  • Output A duty cycle: 50%
  • Output B frequency: 16 MHz / 64 / (180+1) = 1381.2Hz
  • Output B duty cycle: (50+1) / (180+1) = 28.2%

Phase-correct PWM with OCRA top

Using phase-correct PWM with OCRA top,

Where

  • The waveform generation mode bits WGM are set to to 101 for phase-correct PWM with OCRA controlling the top limit
int main() {
   pinMode(3, OUTPUT);  // Set as output
   pinMode(11, OUTPUT); // Set as output
   TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);  // Toggle OC2A on Compare Match and,
                                                     // Clear OC2B on Compare Match when up-counting. Set OC2B on Compare Match when down-counting. 
                                                     //  and phase-correct
   TCCR2B = _BV(WGM22) | _BV(CS22);  // phase-correct and prescale 64
   OCR2A = 180;         // top limit
   OCR2B = 50;          //arbitrary duty cycle for output B (output A is fixed at 50%)
}

Giving

  • Output A frequency: 16 MHz / 64 / 180 / 2 / 2 = 347.2Hz
  • Output A duty cycle: 50%
  • Output B frequency: 16 MHz / 64 / 180 / 2 = 694.4Hz
  • Output B duty cycle: 50 / 180 = 27.8%

As phase-correct gives the most symmetrical waveform, we will continue with this code. However, Fast PWM, as the name suggests is faster.

Expansion

The Timers and their associated pins are as follows (from Timer Interrupts and PWM Pins):

– Pins 5 and 6: controlled by Timer 0
– Pins 9 and 10: controlled by timer 1
– Pins 11 and 3: controlled by timer 2

Note that the prescalar for Timer0 (and Timer1) differs from that of Timer2 and CS02 gives a prescale of 256 en lieu of 64.

So, expanding the phase-correct version for Timer0, and its pins and registers

int main() {
   pinMode(3, OUTPUT);  // Set as output - Timer2
   pinMode(11, OUTPUT); // Set as output - Timer2
   TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20); // Toggle OC2A on Compare Match and,
                                                    // Clear OC2B on Compare Match when up-counting. Set OC2B on Compare Match when down-counting. 
                                                    // and phase-correct    
   TCCR2B = _BV(WGM22) | _BV(CS22);  // phase-correct and prescale 64
   OCR2A = 180;         // top limit
   OCR2B = 50;          //arbitrary duty cycle for output B (output A is fixed at 50%)

   pinMode(5, OUTPUT);  // Set as output - Timer0
   pinMode(6, OUTPUT);  // Set as output - Timer0  
   TCCR0A = _BV(COM0A0) | _BV(COM0B1) | _BV(WGM00);
   TCCR0B = _BV(WGM02) | _BV(CS02);  // prescale 256
   OCR0A = 180;         // top limit
   OCR0B = 50;          //arbitrary duty cycle for output B (output A is fixed at 50%)
}

Similarly, expanding for Timer1, and its pins and registers

int main() {
   pinMode(3, OUTPUT);  // Set as output - Timer2
   pinMode(11, OUTPUT); // Set as output - Timer2
   TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
   TCCR2B = _BV(WGM22) | _BV(CS22);  // prescale 64
   OCR2A = 180;         // top limit
   OCR2B = 50;          //arbitrary duty cycle for output B (output A is fixed at 50%)

   pinMode(5, OUTPUT);  // Set as output - Timer0
   pinMode(6, OUTPUT);  // Set as output - Timer0  
   TCCR0A = _BV(COM0A0) | _BV(COM0B1) | _BV(WGM00);
   TCCR0B = _BV(WGM02) | _BV(CS02);  // prescale 256
   OCR0A = 180;         // top limit
   OCR0B = 50;          //arbitrary duty cycle for output B (output A is fixed at 50%)

   pinMode(9, OUTPUT);  // Set as output - Timer1
   pinMode(10, OUTPUT); // Set as output - Timer1  
   TCCR1A = _BV(COM1A0) | _BV(COM1B1) | _BV(WGM10);
   TCCR1B = _BV(WGM12) | _BV(CS12);  // prescale 256
   OCR1A = 180;         // top limit
   OCR1B = 50;          //arbitrary duty cycle for output B (output A is fixed at 50%)
}

So this gives us six different frequencies… however, we only need four and we have to add a white noise generator. Also, we actually have three pairs the same frequencies (347.2Hz and 694.4Hz). Actually… that is not quite true, as we have already noted, the prescale bits for Timer2 differ from those of Timer0 and Timer1. Setting CS02 and CS12 give a prescale of 256, not 64. So, Timer0 and Timer1 are producing 86.8 Hz and 173.6 Hz.

If we discount one of the timers, lets say Timer1, as we make Timer2 four times as fast as Timer0, by first:

  • adjusting (reducing from 180) the OCR  for both Timer0 and Timer2 to give us a higher base frequency, and then;
  • changing the prescalar value of Timer0, CS02:0, from 64 (011) to 256 (100) – As it has turned out, we already are using a prescalar of 256 for Timer0, so that part of the code remains unchanged

then we should have 4 different frequencies, each with a frequency 50% of next, i.e., 8 kHz, 4 kHz, 2 kHz, and 1 kHz.

Note that it is not yet clear what frequencies, or range of frequencies, are required for the square waves. Nor is it set, what frequency the ATmega (or ATtiny) is running at – 16 MHz or 1 MHz. Lets assume that we are using a 16 MHz clock and the required base frequency (the highest) is 8 kHz (it will probably be nearer 16-20 kHz).

The prescalar values for:

The relevant sections of the AVR ATmega328P datasheet are:

  • 12. 8-bit Timer/Counter0 with PWM
  • 13. 16-bit Timer/Counter1 with PWM
  • 14. Timer/Counter0 and Timer/Counter1 Prescalers
  • 15. 8-bit Timer/Counter2 with PWM and Asynchronous Operation

Most Arduinos run at 16 MHz. Thus, for a required frequency (Freq) of 8 kHz and an assumed clock frequency (Fclock) of 16 MHz, then calculating:

OCR = Fclock/Freq/prescalar/2 = 16M/8K/64/2 = 15.625

Correction: Need to divide by a further two, so

OCR = Fclock/Freq/prescalar/2/2 = 16M/8K/64/2/2 = 7.8125

So, ignoring the exact OCR value but using the approximate value of 16 [no, 8] for a 16 MHz clock gives 8 kHz base (and OCRxBset to 8 [no, 4] for a 50% duty cycle), the code now becomes

int main() {
   pinMode(3, OUTPUT);  // Set as output - Timer2
   pinMode(11, OUTPUT); // Set as output - Timer2
   TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
   TCCR2B = _BV(WGM22) | _BV(CS22);  // prescale 64
   OCR2A = 8;         // top limit for 8 kHz
   OCR2B = 4;          // 50% duty cycle for output B (output A is fixed at 50%)

   pinMode(5, OUTPUT);  // Set as output - Timer0
   pinMode(6, OUTPUT);  // Set as output - Timer0  
   TCCR0A = _BV(COM0A0) | _BV(COM0B1) | _BV(WGM00);
   TCCR0B = _BV(WGM02) | _BV(CS02);  // prescale 256
   OCR0A = 8;         // top limit for 8 kHz
   OCR0B = 4;          // 50% duty cycle for output B (output A is fixed at 50%)
}

Prescalars for other AT microcontrollers

NOTE: for the ATtiny 85, the prescale values are given in Table 12-5 of the Atmel ATtiny25, ATtiny45, ATtiny85 Datasheet – Microchip Technology – page 89, and for Timer1 0111 gives 64. Table 11-6 (page 80) for Timer 0 011 gives 64. See also Table 13-3 page 99 (1011) for ATtiny15 mode.

NOTE: for the ATtiny13, Table 11-9 of the ATtiny13 datasheet – page 73, and for Timer0 011gives 64

White Noise Generator

Implementing a Linear Feedback Shift Register (LFSR) in Arduino isn’t too hard. From Linear-feedback shift register (LFSR) dengan arduino, there are two sketches:

  • Fibonacci
  • Galois

Fibonacci:

uint16_t LFSRBuffer;
 
void setup() {
  Serial.begin(9600);
  Serial.println("LFSR metode Fibonacci");
  Serial.println("http://www.semesin.com/project");
   
  uint16_t nilaiAwal = analogRead(0);
  LFSRFibonacci(nilaiAwal);
  //LFSRFibonacci(100);
}
 
void loop() {
  uint16_t bilanganLFSR = LFSRFibonacci();
  Serial.println(bilanganLFSR);
 
  delay(1000);
}
 
void LFSRFibonacci(uint16_t nilaiAwal)
{
  LFSRBuffer = nilaiAwal;
}
 
uint16_t LFSRFibonacci()
{
    uint16_t bit;
     
    bit  = ((LFSRBuffer >> 0) ^ (LFSRBuffer >> 2) ^ (LFSRBuffer >> 3) ^ (LFSRBuffer >> 5)) & 1;
    LFSRBuffer =  (LFSRBuffer >> 1) | (bit << 15);
    return LFSRBuffer;
}

Galois

uint16_t LFSRBuffer;
 
void setup() {
  Serial.begin(9600);
  Serial.println("LFSR metode Galois");
  Serial.println("http://www.semesin.com/project");
   
  uint16_t nilaiAwal = analogRead(0);
  LFSRGalois(nilaiAwal);
  //LFSRGalois(100);
}
 
void loop() {
  uint16_t bilanganLFSR = LFSRGalois();
  Serial.println(bilanganLFSR);
 
  delay(1000);
}
 
void LFSRGalois(uint16_t nilaiAwal)
{
  LFSRBuffer = nilaiAwal;
}
 
uint16_t LFSRGalois()
{
    unsigned lsb = LFSRBuffer & 1;
    LFSRBuffer >>= 1;
    if (lsb)
    {
        LFSRBuffer ^= 0xB400;
    }
    return LFSRBuffer;
}

However, these two sketches return 16 bit values, and they need to be 8 bit to output to a pin.

Or use a Random Number Generator library, such as Iniesta8/yapRNG.

Or from Audio Frequency White Noise generation using Arduino Mini Pro

Fibonacci

   void generateNoise(){
     unsigned long int reg, newr;
     unsigned char lobit;
     unsigned char b31, b29, b25, b24;
     const int speakerPin = 8;

     b31 = (reg & (1L <> 31;
     b29 = (reg & (1L <> 29;
     b25 = (reg & (1L <> 25;
     b24 = (reg & (1L <> 24;
     lobit = b31 ^ b29 ^ b25 ^ b24;
     newr = (reg << 1) | lobit;
     reg = newr;
     digitalWrite (speakerPin, reg & 1);
     delayMicroseconds (50); // Changing this value changes the frequency.
}

Galois – possibly faster than the fibonacci

#define speakerPin 8

unsigned long lastClick;

void setup() {
  // put your setup code here, to run once:
   pinMode(speakerPin,OUTPUT);
   lastClick = micros();   
}


/* initialize with any 32 bit non-zero  unsigned long value. */

#define LFSR_INIT  0xfeedfaceUL

/* Choose bits 32, 30, 26, 24 from  http://arduino.stackexchange.com/a/6725/6628
 *  or 32, 22, 2, 1 from 
 *  http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
 *  or bits 32, 16, 3,2  or 0x80010006UL per http://users.ece.cmu.edu/~koopman/lfsr/index.html 
 *  and http://users.ece.cmu.edu/~koopman/lfsr/32.dat.gz
 */  

#define LFSR_MASK  ((unsigned long)( 1UL<<31 | 1UL <<15 | 1UL <<2 | 1UL <<1  ))

unsigned int generateNoise(){    // See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs 
   static unsigned long int lfsr = LFSR_INIT;  /* 32 bit init, nonzero */    
/* If the output bit is 1, apply toggle mask.  
 * The value has 1 at bits corresponding                                     
 * to taps, 0 elsewhere. 
 */
   if(lfsr & 1) { lfsr =  (lfsr >>1) ^ LFSR_MASK ; return(1);}
   else         { lfsr >>= 1;                      return(0);}
}

void loop() {
      /* ... */
      if ((micros() - lastClick) > 50 ) { // Changing this value changes the frequency.
        lastClick = micros();
        digitalWrite (speakerPin, generateNoise());
      }
}

Putting it all together

Now, we can join the square wave timer PWM code and LFSR sketches

const int speakerPin = 8;
unsigned long lastClick;

void setup() {
  // put your setup code here, to run once:
   pinMode(speakerPin,OUTPUT);
   lastClick = micros();   

   pinMode(3, OUTPUT);  // Set as output - Timer2
   pinMode(11, OUTPUT); // Set as output - Timer2
   TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
   TCCR2B = _BV(WGM22) | _BV(CS22);  // prescale 64
   OCR2A = 8;         // top limit for 8 kHz
   OCR2B = 4;          // 50% duty cycle for output B (output A is fixed at 50%)

   pinMode(5, OUTPUT);  // Set as output - Timer0
   pinMode(6, OUTPUT);  // Set as output - Timer0  
   TCCR0A = _BV(COM0A0) | _BV(COM0B1) | _BV(WGM00);
   TCCR0B = _BV(WGM02) | _BV(CS02);  // prescale 256
   OCR0A = 8;         // top limit for 8 kHz
   OCR0B = 4;          // 50% duty cycle for output B (output A is fixed at 50%)
}


/* initialize with any 32 bit non-zero  unsigned long value. */

#define LFSR_INIT  0xfeedfaceUL

/* Choose bits 32, 30, 26, 24 from  http://arduino.stackexchange.com/a/6725/6628
 *  or 32, 22, 2, 1 from 
 *  http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
 *  or bits 32, 16, 3, 2  or 0x80010006UL per http://users.ece.cmu.edu/~koopman/lfsr/index.html 
 *  and http://users.ece.cmu.edu/~koopman/lfsr/32.dat.gz
 */  

#define LFSR_MASK  ((unsigned long)( 1UL << 31 | 1UL << 15 | 1UL << 2 | 1UL << 1 ))

// See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs
unsigned int generateNoise(){
   static unsigned long int lfsr = LFSR_INIT;  /* 32 bit init, nonzero */
/* If the output bit is 1, apply toggle mask.
 * The value has 1 at bits corresponding                                     
 * to taps, 0 elsewhere. 
 */

   if(lfsr & 1) { lfsr =  (lfsr >>1) ^ LFSR_MASK ; return(1);}
   else         { lfsr >>= 1;                      return(0);}
}

void loop() {
   /* ... */
   if ((micros() - lastClick) > 50 ) { // Changing this value changes the frequency.
      lastClick = micros();
      digitalWrite (speakerPin, generateNoise());
   }
}

UPDATE: However, since writing the above code, I have discovered that the frequencies are not double of each other (see Further reading at the top), and so this technique will not work..!

However, if one was prepared to use approximations to the required frequencies (don’t forget that the original frequencies were probably approximations themselves, based on available capacitor/resistor values), then one could use the following frequency pairs:

  • 1.15 kHz and 575 Hz
  • 820 Hz and 410 Hz

Each of the lower frequencies is about 100 Hz too high.

OCR2A = Fclock/Freq/prescalar/2/2 = 16M/1.15K/64/2/2 = 54.34 ≈ 53

OCR2B = 27

OCR0A = Fclock/Freq/prescalar/2/2 = 16M/820/64/2/2 = 76.219 ≈ 76

OCR0B = 38

Note that the prescaler in this case for Timer0 is now 64 (011) and not 256 (100) as before.

setup() now becomes

void setup() {
 // put your setup code here, to run once:
  pinMode(speakerPin,OUTPUT);
  lastClick = micros();

  pinMode(3, OUTPUT); // Set as output - Timer2
  pinMode(11, OUTPUT); // Set as output - Timer2
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
  TCCR2B = _BV(WGM22) | _BV(CS22); // prescale 64
  OCR2A = 53; // top limit for 8 kHz
  OCR2B = 27; // 50% duty cycle for output B (output A is fixed at 50%)

  pinMode(5, OUTPUT); // Set as output - Timer0
  pinMode(6, OUTPUT); // Set as output - Timer0
  TCCR0A = _BV(COM0A0) | _BV(COM0B1) | _BV(WGM00);
  TCCR0B = _BV(WGM02) | _BV(CS01) | _BV(CS00); // prescale 64
  OCR0A = 76; // top limit for 8 kHz
  OCR0B = 38; // 50% duty cycle for output B (output A is fixed at 50%)
}

UPDATE: There is an issue with using Timer0, as it will conflict with the use of micros() and lastClick(), which is used in the LSFR. See Does millis() conflict with the PWM pins associated with timer 0? and Arduino uno PWM CTC mode – strange behaviour on interrupt. From Re: Timer Interrupts and PWM Pins:

Arduino uses TIMER0 for the timing. You should not change that. You can do whatever you want with TIMER1 and TIMER2. Some functions or libraries use those timers (pwm, tone(), and many more), so you have to be careful how they are used.

So while the square waves will operate as expected the LSFR will not. It would be necessary to switch to using Timer1 (as is done in Attempt#3).

Attempt#3 – Soft timers

Attempting to use a combination of the CTC hardware and soft timers, where the highest frequency is used as a base clock rate and then use software to divide the frequency for the other three signals.

Knowing the frequencies

  • 1.15 kHz
  • 820 Hz
  • 317 Hz
  • 465 Hz

and trying to determine a relationship between them and there doesn’t seem to be one. So, simple division of the highest clock rate will not work.

Taking an idea from Generating 2 different frequencies only on timer 1, it is necessary to find the least common multiple (LCM) of 1.15k, 820, 465, 317, and use a frequency equal to the LCM as the base clock rate. Then from that, in software divide that base clock rate to obtain all four square waves.

Finding the LCM could be done by hand, or using an online LCM calculator.

Using the online calculator:

For the values: 1150, 820, 465, 317
https://www.calculatorsoup.com/calculators/math/lcm.php?input=1150%2C+820%2C+465%2C+317&action=solve
LCM = 2780058300
LCM = 2,780,058,300

which is clearly not that much use, as the clock would need to be more than 5 GHz. Adjusting the figures to find a lower LCM

For the values: 1150, 820, 465, 316
https://www.calculatorsoup.com/calculators/math/lcm.php?input=1150%2C+820%2C+465%2C+316&action=solve
LCM = 692822100
LCM = 692,822,100

Still too high.

For the values:
1150, 820, 465, 320
https://www.calculatorsoup.com/calculators/math/lcm.php?input=1150%2C+820%2C+465%2C+320&action=solve
LCM = 140318400
LCM = 140,318,400

Still too high but getting lower

For the values:
1150, 820, 460, 320
https://www.calculatorsoup.com/calculators/math/lcm.php?input=1150%2C+820%2C+460%2C+320&action=solve
LCM = 1508800
LCM = 1,508,800

This value is just about usable with a 8/16 MHz clock. It would be of no use for a 1 MHz clock frequency though.

For the values:
1150, 820, 464, 320
https://www.calculatorsoup.com/calculators/math/lcm.php?input=1150%2C+820%2C+464%2C+320&action=solve
LCM = 43755200

With this last set of values we have gone off track again.

Taking the  penultimate LCM of 1508800, we would need to set a hardware timer to obtain this and then in the ISR create four counters that toggle their outputs at the following counts: 1312, 1840, 3280, and 4715

Using the example from Newbie’s Guide to AVR Timers – Part Five – CTC Mode using Interrupts:

#include 
#include 

int main (void)
{
   DDRB |= (1 << 0); // Set LED as output

   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

   TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt

   sei(); //  Enable global interrupts

   OCR1A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

   TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64

   for (;;)
   {

   }
}

ISR(TIMER1_COMPA_vect)
{
   PORTB ^= (1 << 0); // Toggle the LED
}

Note that the example in the link uses a 1 MHz clock, whereas we are using a 16 MHz

16M/1508800 = 10.604, so even further approximations with be made. Taking 11 as the nearest value, then that gives a base frequency of 1454545.45 (1.454545 MHz). Taking 10, gives 1.6 MHz (obviously).

To get 1.15 KHz, that base frequency would need dividing by 1264.822. Dividing 1454545.45 by 1264 gives a frequency of, 1150.747 Hz. Dividing 1454545.45 by 1265 gives a frequency of, 1149.838 Hz.

To get 820 Hz, that base frequency would need dividing by 1773.835. Dividing 1454545.45 by 1773 gives a frequency of, 820.386 Hz. Dividing 1454545.45 by 1774 gives a frequency of, 819.92 Hz.

To get 460 Hz, that base frequency would need dividing by 3162.055. Dividing 1454545.45 by 3162 gives a frequency of, 460.008 Hz. Dividing 1454545.45 by 3163 gives a frequency of, 459.862 Hz.

To get 320 Hz, that base frequency would need dividing by 4545.45. Dividing 1454545.45 by 4545 gives a frequency of, 320.03 Hz. Dividing 1454545.45 by 4546 gives a frequency of, 319.96 Hz.

All of these are pretty reasonable approximations.  Of course, using the base frequency of 1454545.45 Hz, we can strive to obtain closer to the original lower two values (465 Hz and 316 Hz), which we had approximated to 460 Hz and 320 Hz, in order to determine the lowest feasible LCM.

To get to original 465 Hz, that base frequency would need dividing by 3128.0547. Dividing 1454545.45 by 3128 gives a frequency of, 465.008 Hz. Dividing 3129 by 3163 gives a frequency of, 464.859 Hz.

To get 316 Hz, that base frequency would need dividing by 4602.99. Dividing 1454545.45 by 4602 gives a frequency of, 316.068 Hz. Dividing 1454545.45 by 4603 gives a frequency of, 315.999 Hz.

So to recap: For a 16 MHz clock frequency, using Timer1 with a clock divider of 11 (without a prescalar, or rather a prescalar of 1 (001) and then software dividers (base frequency divider values) of 1265, 1774, 3128, and 4603, we get pretty damn close to the original frequencies.

Setting up the CTC interrupt appropriately:

#include 
#include 

int main (void)
{
   DDRB |= (1 << 0); // Set LED as output

   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

   TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt

   sei(); //  Enable global interrupts

   OCR1A   = 15624; // Set CTC compare value to 1454545.45 Hz at 16 MHz AVR clock, with a prescaler of 1

   TCCR1B |= (1 << CS10); // Start timer at Fcpu/1

   for (;;)
   {

   }
}

ISR(TIMER1_COMPA_vect)
{
   PORTB ^= (1 << 0); // Toggle the LED
}

Note that in this example with have to:

  • Enable global interrupts (sei), which we didn’t have to do in the previous Attempts (#1 and #2)
  • Enable the CTC interrupt
  • Have an ISR (Interrupt Service Routine)
  • We are also setting the output differently

However, this, as it stands, only gives us the base frequency on digital pin 8. We have to add the software timers.

Again referring to Port Registers for port to pin mappings;

The chips used on the Arduino board (the ATmega8 and ATmega168) have three ports:

  • B (digital pin 8 to 13)

we will use digital pins 8, 9, 10 and 11 for the square wave. These are set by setting bits 0-3 of DDRB, the Port B Data Direction Register:

DDRB |= (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3); // Set digital pins 8-11 as outputs

or

DDRB = DDRB | B01111;  // Set digital pins 8-11 as outputs

Now for the software timers themselves, they are global integer variables, as they are used in the ISR:

int squarewave_1150 = 0;
int squarewave_820 = 0;
int squarewave_465 = 0;
int squarewave_316 = 0;

and the ISR:

ISR(TIMER1_COMPA_vect) {
  squarewave_1150++;
  squarewave_820++;
  squarewave_465++;
  squarewave_316++;

  if (squarewave_1150 == 1265) {
    PORTB ^= (1 << 0); // Toggle the 1.15 KHz output
    squarewave_1150 = 0;
  }
  if (squarewave_820 == 1774) {
    PORTB ^= (1 << 1); // Toggle the 820 Hz output
    squarewave_820 = 0;
  }
  if (squarewave_465 == 3128) {
    PORTB ^= (1 << 2); // Toggle the 465 Hz output
    squarewave_465 = 0;
  }
  if (squarewave_316 == 4603) {
    PORTB ^= (1 << 3); // Toggle the 316 Hz output
    squarewave_316 = 0;
  }
}

Now, there is an immediate problem. The compare values used (the base frequency divider values) will actually result in frequencies which are half of the expected values. Why? Because the toggling of the square wave output, when these values are reached, means that the period of the square wave is twice the length of that which we require.

So the compare values used for toggling the wave output are actually half of software base frequency divider values.

This will cause further inaccuracies in the frequencies, where the base frequency divider values are not exactly divisible by two, and means that we should probably consider decreasing or increasing the base frequency divider values, for the odd values, i.e. the base frequency divider values for 1.15 kHz and 316 Hz. Using 1264 for the 1.15 kHz and 4602 for 316 Hz (see the previous calculations above for the errors induced +0.474 Hz and +0.068 Hz, respectively).

So, dividing the base frequency divider values by two:

ISR(TIMER1_COMPA_vect) {
  squarewave_1150++;
  squarewave_820++;
  squarewave_465++;
  squarewave_316++;

  if (squarewave_1150 == 1264/2) {
    PORTB ^= (1 << 0); // Toggle the 1.15 KHz output
    squarewave_1150 = 0;
  }
  if (squarewave_820 == 1774/2) {
    PORTB ^= (1 << 1); // Toggle the 820 Hz output
    squarewave_820 = 0;
  }
  if (squarewave_465 == 3128/2) {
    PORTB ^= (1 << 2); // Toggle the 465 Hz output
    squarewave_465 = 0;
  }
  if (squarewave_316 == 4602/2) {
    PORTB ^= (1 << 3); // Toggle the 316 Hz output
    squarewave_316 = 0;
  }
}

Putting it together, and defining some const int constants for readability gives

const int BFDV_1150 = 1264; // base frequency divider value for 1.15 KHz
const int BFDV_820 = 1774; // base frequency divider value for 820 Hz
const int BFDV_465 = 3128; // base frequency divider value for 465 Hz
const int BFDV_316 = 4602; // base frequency divider value for 316 Hz

const int HalfPeriodCompare_1150 = BFDV_1150/2; // Half period toggle compare value for 1.15 kHz
const int HalfPeriodCompare_820 = BFDV_820/2; // Half period toggle compare value for 820 Hz
const int HalfPeriodCompare_465 = BFDV_465/2; // Half period toggle compare value for 465 Hz
const int HalfPeriodCompare_316 = BFDV_316/2; // Half period toggle compare value for 316 Hz

const int DigitalPin8 = 0;
const int DigitalPin9 = 1;
const int DigitalPin10 = 2;
const int DigitalPin11 = 3;

int squarewave_1150 = 0;
int squarewave_820 = 0;
int squarewave_465 = 0;
int squarewave_316 = 0;

int main (void) {
  DDRB |= (1 << DigitalPin8 | 1 << DigitalPin9 | 1 << DigitalPin10 | 1 << DigitalPin11); // Set digital pins 8-11 as outputs
  TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
  TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
  sei(); // Enable global interrupts
  OCR1A = 15624; // Set CTC compare value to 1454545.45 Hz at 16 MHz AVR clock, with a prescaler of 1
  TCCR1B |= (1 << CS10); // Start timer at Fcpu/1
  for (;;) { } 
}

ISR(TIMER1_COMPA_vect) {
  squarewave_1150++;
  squarewave_820++;
  squarewave_465++;
  squarewave_316++;

  if (squarewave_1150 == HalfPeriodCompare_1150) {
    PORTB ^= (1 << DigitalPin8); // Toggle the 1.15 KHz output
    squarewave_1150 = 0;
  }
  if (squarewave_820 == HalfPeriodCompare_820) {
    PORTB ^= (1 << DigitalPin9); // Toggle the 820 Hz output
    squarewave_820 = 0;
  }
  if (squarewave_465 == HalfPeriodCompare_465) {
    PORTB ^= (1 << DigitalPin10); // Toggle the 465 Hz output
    squarewave_465 = 0;
  }
  if (squarewave_316 == HalfPeriodCompare_316) {
    PORTB ^= (1 << DigitalPin11); // Toggle the 316 Hz output
    squarewave_316 = 0;
  }
}

Adding in the noise generator

// Noise chip for LDB-1 using ATmega 328

const int BFDV_1150 = 1264; // base frequency divider value for 1.15 KHz
const int BFDV_820 = 1774; // base frequency divider value for 820 Hz
const int BFDV_465 = 3128; // base frequency divider value for 465 Hz
const int BFDV_316 = 4602; // base frequency divider value for 316 Hz

const int HalfPeriodCompare_1150 = BFDV_1150/2; // Half period toggle compare value for 1.15 kHz
const int HalfPeriodCompare_820 = BFDV_820/2; // Half period toggle compare value for 820 Hz
const int HalfPeriodCompare_465 = BFDV_465/2; // Half period toggle compare value for 465 Hz
const int HalfPeriodCompare_316 = BFDV_316/2; // Half period toggle compare value for 316 Hz

const int DigitalPin8 = 0;
const int DigitalPin9 = 1;
const int DigitalPin10 = 2;
const int DigitalPin11 = 3;

int squarewave_1150 = 0;
int squarewave_820 = 0;
int squarewave_465 = 0;
int squarewave_316 = 0;

const int speakerPin = 8;
unsigned long lastClick;


/* initialize with any 32 bit non-zero unsigned long value. */
 #define LFSR_INIT 0xfeedfaceUL
 /* Choose bits 32, 30, 26, 24 from http://arduino.stackexchange.com/a/6725/6628
  * or 32, 22, 2, 1 from * http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
  * or bits 32, 16, 3, 2 or 0x80010006UL per http://users.ece.cmu.edu/~koopman/lfsr/index.html
  * and http://users.ece.cmu.edu/~koopman/lfsr/32.dat.gz
  */
 #define LFSR_MASK ((unsigned long)( 1UL << 31 | 1UL << 15 | 1UL << 2 | 1UL << 1 )) // See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs
 unsigned int generateNoise(){
   static unsigned long int lfsr = LFSR_INIT; /* 32 bit init, nonzero */
 /* If the output bit is 1, apply toggle mask.
  * The value has 1 at bits corresponding
  * to taps, 0 elsewhere.
  */
   if(lfsr & 1) { lfsr = (lfsr >>1) ^ LFSR_MASK ; return(1);}
   else { lfsr >>= 1; return(0);}
 } 


int main (void) {
  pinMode(speakerPin,OUTPUT);
  lastClick = micros(); 

  DDRB |= (1 << DigitalPin8 | 1 << DigitalPin9 | 1 << DigitalPin10 | 1 << DigitalPin11); // Set digital pins 8-11 as outputs
  TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
  TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
  sei(); // Enable global interrupts
  OCR1A = 15624; // Set CTC compare value to 1454545.45 Hz at 16 MHz AVR clock, with a prescaler of 1
  TCCR1B |= (1 << CS10); // Start timer at Fcpu/1
  for (;;) {
    if ((micros() - lastClick) > 50 ) { // Changing this value changes the frequency.
      lastClick = micros();
      digitalWrite (speakerPin, generateNoise());
    }
  }
}

ISR(TIMER1_COMPA_vect) {
  squarewave_1150++;
  squarewave_820++;
  squarewave_465++;
  squarewave_316++;

  if (squarewave_1150 == HalfPeriodCompare_1150) {
    PORTB ^= (1 << DigitalPin8); // Toggle the 1.15 KHz output
    squarewave_1150 = 0;
  }
  if (squarewave_820 == HalfPeriodCompare_820) {
    PORTB ^= (1 << DigitalPin9); // Toggle the 820 Hz output
    squarewave_820 = 0;
  }
  if (squarewave_465 == HalfPeriodCompare_465) {
    PORTB ^= (1 << DigitalPin10); // Toggle the 465 Hz output
    squarewave_465 = 0;
  }
  if (squarewave_316 == HalfPeriodCompare_316) {
    PORTB ^= (1 << DigitalPin11); // Toggle the 316 Hz output
    squarewave_316 = 0;
  }
}

That’s it in ​main() format. Using setup() and loop()gives us:

// Noise chip for LDB-1 using ATmega 328

const int BFDV_1150 = 1264; // base frequency divider value for 1.15 KHz
const int BFDV_820 = 1774; // base frequency divider value for 820 Hz
const int BFDV_465 = 3128; // base frequency divider value for 465 Hz
const int BFDV_316 = 4602; // base frequency divider value for 316 Hz

const int HalfPeriodCompare_1150 = BFDV_1150/2; // Half period toggle compare value for 1.15 kHz
const int HalfPeriodCompare_820 = BFDV_820/2; // Half period toggle compare value for 820 Hz
const int HalfPeriodCompare_465 = BFDV_465/2; // Half period toggle compare value for 465 Hz
const int HalfPeriodCompare_316 = BFDV_316/2; // Half period toggle compare value for 316 Hz

const int DigitalPin8 = 0;
const int DigitalPin9 = 1;
const int DigitalPin10 = 2;
const int DigitalPin11 = 3;

int squarewave_1150 = 0;
int squarewave_820 = 0;
int squarewave_465 = 0;
int squarewave_316 = 0;

const int speakerPin = 8;
unsigned long lastClick;
const int kNoiseFrequency = 50;


/* initialize with any 32 bit non-zero unsigned long value. */
 #define LFSR_INIT 0xfeedfaceUL
 /* Choose bits 32, 30, 26, 24 from http://arduino.stackexchange.com/a/6725/6628
  * or 32, 22, 2, 1 from * http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
  * or bits 32, 16, 3, 2 or 0x80010006UL per http://users.ece.cmu.edu/~koopman/lfsr/index.html
  * and http://users.ece.cmu.edu/~koopman/lfsr/32.dat.gz
  */
 #define LFSR_MASK ((unsigned long)( 1UL << 31 | 1UL << 15 | 1UL << 2 | 1UL << 1 )) // See https://en.wikipedia.org/wiki/Linear_feedback_shift_register#Galois_LFSRs
 unsigned int generateNoise(){
   static unsigned long int lfsr = LFSR_INIT; /* 32 bit init, nonzero */
 /* If the output bit is 1, apply toggle mask.
  * The value has 1 at bits corresponding
  * to taps, 0 elsewhere.
  */
   if(lfsr & 1) { lfsr = (lfsr >>1) ^ LFSR_MASK ; return(1);}
   else { lfsr >>= 1; return(0);}
 } 

void setup (void) {
  pinMode(speakerPin,OUTPUT);
  lastClick = micros(); 

  DDRB |= (1 << DigitalPin8 | 1 << DigitalPin9 | 1 << DigitalPin10 | 1 << DigitalPin11); // Set digital pins 8-11 as outputs
  TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
  TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt
  sei(); // Enable global interrupts
  OCR1A = 15624; // Set CTC compare value to 1454545.45 Hz at 16 MHz AVR clock, with a prescaler of 1
  TCCR1B |= (1 << CS10); // Start timer at Fcpu/1
}
 
void loop() {
  if ((micros() - lastClick) > kNoiseFrequency ) { // Changing this value changes the frequency.
    lastClick = micros();
    digitalWrite (speakerPin, generateNoise());
  }
}

ISR(TIMER1_COMPA_vect) {
  squarewave_1150++;
  squarewave_820++;
  squarewave_465++;
  squarewave_316++;

  if (squarewave_1150 == HalfPeriodCompare_1150) {
    PORTB ^= (1 << DigitalPin8); // Toggle the 1.15 KHz output
    squarewave_1150 = 0;
  }
  if (squarewave_820 == HalfPeriodCompare_820) {
    PORTB ^= (1 << DigitalPin9); // Toggle the 820 Hz output
    squarewave_820 = 0;
  }
  if (squarewave_465 == HalfPeriodCompare_465) {
    PORTB ^= (1 << DigitalPin10); // Toggle the 465 Hz output
    squarewave_465 = 0;
  }
  if (squarewave_316 == HalfPeriodCompare_316) {
    PORTB ^= (1 << DigitalPin11); // Toggle the 316 Hz output
    squarewave_316 = 0;
  }
}

 

Note that the #includes from Attempt#1 are not actually required.

That’s all folks! Happy noise making…

 

 

 

 

 

 

 

 

 

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s