Created
August 16, 2017 07:45
-
-
Save xobs/74f19632820a340f7af5c34c12da79b2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Arduino.h" | |
#include "ChibiOS.h" | |
#include "kl02.h" | |
#include "memio.h" | |
// Enable interpolation to make the output smoother. | |
// Set to 0 to disable interpolation. | |
// Note that some instruments don't support interpolation. | |
#define INTERPOLATION_ENABLED 1 | |
// Sets the maximum value of the phase accumulator, which is | |
// used to skip through the sample array. | |
#define PHASEACC_MAX 131072L | |
// The system is running off of a 32.768 kHz crystal going through | |
// a 1464x FLL multiplier, giving a system frequency of | |
// 47.972352 MHz. | |
// We set the PWM counter to 258, which gives a PWM period of 185.939 kHz. | |
// Happily, 185.939 is evenly divisible by 13, giving us an actual sample | |
// rate of 14303 kHz, assuming we delay 13 times. | |
#define PWM_DELAY_LOOPS 3 | |
// The number of ticks that the sound system has gone through. | |
// Overflows after about three days, at 14 kHz. | |
volatile uint32_t global_tick_counter; | |
// The next sample to be played, nominally between -128 and 127 | |
static int32_t next_sample; | |
// Nonzero if a sample has been queued, zero if the sample buffer is empty. | |
static volatile uint8_t sample_queued; | |
static int pwm0_stable_timer(void) | |
{ | |
static int loops = 0; | |
/* Reset the timer IRQ, to allow us to fire again next time */ | |
writel(TPM0_STATUS_CH1F | TPM0_STATUS_CH0F | TPM0_STATUS_TOF, TPM0_STATUS); | |
if (loops++ > PWM_DELAY_LOOPS) { | |
int32_t scaled_sample = next_sample + 130; | |
if (scaled_sample > 255) | |
scaled_sample = 255; | |
if (scaled_sample <= 0) | |
scaled_sample = 1; | |
writel(scaled_sample, TPM0_C1V); | |
writel(scaled_sample, TPM0_C0V); | |
loops = 0; | |
sample_queued = 0; | |
global_tick_counter++; | |
} | |
return 0; | |
} | |
static void prepare_pwm() | |
{ | |
// Write dummy values out, to configure PWM mux | |
pinMode(0, OUTPUT); | |
analogWrite(0, 63); | |
pinMode(1, OUTPUT); | |
analogWrite(1, 63); | |
// Disable TPM0, allowing us to configure it | |
writel(0, TPM0_SC); | |
// Also disable both channels, which are running from the | |
// calls to analogWrite() above | |
writel(0, TPM0_C0SC); | |
writel(0, TPM0_C1SC); | |
// Configure the TPM to use the MCGFLLCLK (~32 MHz?) | |
writel(readl(SIM_SOPT2) | (1 << 24), SIM_SOPT2); | |
// We've picked pin 0, which is on TPM0_CH1 | |
writel(256, TPM0_MOD); | |
writel(0, TPM0_CNT); | |
writel(TPM0_C0SC_MSB | TPM0_C0SC_ELSB, TPM0_C0SC); | |
writel(TPM0_C1SC_MSB | TPM0_C1SC_ELSA, TPM0_C1SC); | |
writel(100, TPM0_C1V); | |
writel(100, TPM0_C0V); | |
writel(TPM0_SC_TOF | TPM0_SC_TOIE | TPM0_SC_CMOD(1) | TPM0_SC_PS(0), TPM0_SC); // Enable TPM0 | |
/* Enable the IRQ in the system-wide interrupt table */ | |
attachFastInterrupt(PWM0_IRQ, pwm0_stable_timer); | |
} | |
void setup(void) | |
{ | |
prepare_pwm(); | |
enableInterrupt(PWM0_IRQ); | |
} | |
void loop(void) | |
{ | |
// If a sample is still in the buffer, don't do anything. | |
if (sample_queued) | |
return; | |
uint32_t t = global_tick_counter; | |
uint32_t y = 0; | |
uint32_t x = 0; | |
next_sample = (((int)(3e3/(y=t&16383))&1)*35) + | |
(x=t*("6689"[t>>16&3]&15)/24&127)*y/4e4 + | |
(((t>>8^t>>10)|t>>14|x)&63); | |
sample_queued = 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment