Data Structures | Defines | Typedefs | Functions | Variables

xpal_noise.c File Reference

#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/atomic.h>
#include <avr/power.h>
#include <xpal_noise.h>

Data Structures

struct  noise_part_s
struct  sample_s

Defines

#define FILL(x)   {x, sizeof(x)}

Typedefs

typedef struct noise_part_s noise_part_t

Functions

 ISR (TIMER0_OVF_vect, ISR_BLOCK)
void xpal_noise_init (void)
 init noise generator
void xpal_noise_gc (void)
 garbage-collect noise parts
void xpal_output_noise (uint16_t duration, uint8_t value, volatile uint8_t *pdone)
 output some noise

Variables

noise_part_t *volatile noise_playing
 currently playing sample
noise_part_tnoise_last
 pointer to last sample in queue
noise_part_t *volatile noises_done
 list of samples awaiting GC
const uint8_t sample1[] PROGMEM

Detailed Description


Typedef Documentation

typedef struct noise_part_s noise_part_t

We build a singly-linked list of samples to play. Each sample has a pointer to a list of values to output to the PWM generator (in a circular way) and a duration.

When the sample has used up its timeslice (as measured by duration), the next sample will get started and the current sample will be put in a list for later garbage collection (we don't want to do the free() in the ISR).


Function Documentation

void xpal_noise_init ( void   ) 

init noise generator

initialize the noise generator (Timer0 in PWM mode)

{
  DDRG |= _BV(DDG5);

  /* fast PWM, normal output mode on OC0B */
  TCCR0A = (TCCR0A & ~(_BV(COM0B1)|_BV(COM0B0)|_BV(WGM01)|_BV(WGM00)))
    | (_BV(COM0B1)|(0*_BV(COM0B0))|_BV(WGM01)|_BV(WGM00));
}

void xpal_output_noise ( uint16_t  duration,
uint8_t  value,
volatile uint8_t *  pdone 
)

output some noise

Parameters:
duration time after the noise should stop
value 0 - stop noise, otherwise play
pdone pointer to a uint8_t which gets set to !=0 when playing this part has finished. Pass NULL when not wanted.

values: 1 - 3600 Hz sine wave 2 - 7200 Hz sine wave

{
  if (value) {
    const struct sample_s *s;
    uint8_t sz;
    noise_part_t * p = NULL;
    uint8_t * v = NULL;

    /* bounds check */
    if (value >= sizeof(samples)/sizeof(samples[0])) value = 1;

    /* prepare new part for queue */
    s = &samples[value];
    sz = pgm_read_byte (&s->sz);
    
    while (1) {
      if (!v) v = malloc (sz);
      if (!p) p = malloc(sizeof(noise_part_t));
      if (v && p) break;
      /* malloc() failed - try GC if useful */
      if (!noises_done) {
        /* GC won't help (yet?) - free() malloced spaces and ignore sample */
        free (v);
        free (p);
        if (pdone) *pdone = -1;
        return;
      }
      xpal_noise_gc ();
    }
    p->values = v;
    p->num_values = sz/sizeof(uint8_t);
    p->flags.malloced_struct = p->flags.malloced_values = 1;
    memcpy_P (v, (const uint8_t*)pgm_read_word (&s->v), sz);
    p->duration = duration;
    p->next = NULL;
    p->pdone = pdone;

    /* Link newly-prepared part at end of queue.
     * Block is necessary to prevent a race condition with the ISR
     * modifying noise_playing or *noise_playing.
     */
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
      if (!noise_playing) {
        noise_playing = p;
        xpal_noise_init ();
        xpal_noise_enable ();
      } else {
        noise_last->next = p;
      }
      noise_last = p;
    }
  } else {
    xpal_noise_disable ();
  }
  xpal_noise_gc ();
}


Variable Documentation

const char _etext PROGMEM
Initial value:
  { 128, 176, 218, 245, 255, 245, 217, 176,
    127, 79, 37, 10, 0, 10, 37, 79 }