Skip to content

Commit 61dab5c

Browse files
Move arcada object to globals, start using arcada timer in voice mod
1 parent c4d8546 commit 61dab5c

3 files changed

Lines changed: 18 additions & 51 deletions

File tree

M4_Eyes/M4_Eyes.ino

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
#define GLOBAL_VAR
3838
#include "globals.h"
3939

40-
Adafruit_Arcada arcada;
41-
4240
// Global eye state that applies to all eyes (not per-eye):
4341
bool eyeInMotion = false;
4442
float eyeOldX, eyeOldY, eyeNewX, eyeNewY;

M4_Eyes/globals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#endif
2020

2121
// GLOBAL VARIABLES --------------------------------------------------------
22+
23+
GLOBAL_VAR Adafruit_Arcada arcada;
24+
2225
#define MAX_DISPLAY_SIZE 240
2326
GLOBAL_VAR int DISPLAY_SIZE GLOBAL_INIT(240); // Start with assuming a 240x240 display
2427
GLOBAL_VAR uint32_t stackReserve GLOBAL_INIT(5192); // See image-loading code

M4_Eyes/pdmvoice.cpp

Lines changed: 15 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,13 @@
33

44
#if defined(ADAFRUIT_MONSTER_M4SK_EXPRESS)
55

6+
#include "globals.h"
67
#include <SPI.h>
78

89
#define MIN_PITCH_HZ 65
910
#define MAX_PITCH_HZ 1600
1011
#define TYP_PITCH_HZ 175
1112

12-
// Playback timer stuff - use TC3 on MONSTER M4SK (no TC4 on this board)
13-
#define TIMER TC3
14-
#define TIMER_IRQN TC3_IRQn
15-
#define TIMER_IRQ_HANDLER TC3_Handler
16-
#define TIMER_GCLK_ID TC3_GCLK_ID
17-
#define TIMER_GCM_ID GCM_TC2_TC3
18-
1913
// PDM mic allows 1.0 to 3.25 MHz max clock (2.4 typical).
2014
// SPI native max is is 24 MHz, so available speeds are 12, 6, 3 MHz.
2115
#define SPI_BITRATE 3000000
@@ -103,6 +97,7 @@ static int16_t playbackIndexJumped;
10397
static uint16_t nextOut = 2048;
10498

10599
float voicePitch(float p);
100+
static void playCallback(void);
106101

107102
// START PITCH SHIFT (no arguments) ----------------------------------------
108103

@@ -150,37 +145,7 @@ bool voiceSetup(bool modEnable) {
150145

151146
analogWriteResolution(12);
152147

153-
// Feed TIMER off GCLK1 (already set to 48 MHz by Arduino core)
154-
GCLK->PCHCTRL[TIMER_GCLK_ID].bit.CHEN = 0; // Disable channel
155-
while(GCLK->PCHCTRL[TIMER_GCLK_ID].bit.CHEN); // Wait for disable
156-
GCLK_PCHCTRL_Type pchctrl;
157-
pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK1_Val;
158-
pchctrl.bit.CHEN = 1;
159-
GCLK->PCHCTRL[TIMER_GCLK_ID].reg = pchctrl.reg;
160-
while(!GCLK->PCHCTRL[TIMER_GCLK_ID].bit.CHEN); // Wait for enable
161-
162-
// Disable timer before configuring it
163-
TIMER->COUNT16.CTRLA.bit.ENABLE = 0;
164-
while(TIMER->COUNT16.SYNCBUSY.bit.ENABLE);
165-
166-
// 16-bit counter mode, 1:1 prescale, match-frequency generation mode
167-
TIMER->COUNT16.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16;
168-
TIMER->COUNT16.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV1_Val;
169-
TIMER->COUNT16.WAVE.bit.WAVEGEN = TC_WAVE_WAVEGEN_MFRQ_Val;
170-
171-
TIMER->COUNT16.CTRLBCLR.reg = TC_CTRLBCLR_DIR; // Count up
172-
while(TIMER->COUNT16.SYNCBUSY.bit.CTRLB);
173-
174-
voicePitch(1.0); // Set timer interval
175-
176-
TIMER->COUNT16.INTENSET.reg = TC_INTENSET_OVF; // Overflow interrupt
177-
NVIC_DisableIRQ(TIMER_IRQN);
178-
NVIC_ClearPendingIRQ(TIMER_IRQN);
179-
NVIC_SetPriority(TIMER_IRQN, 0); // Top priority
180-
NVIC_EnableIRQ(TIMER_IRQN);
181-
182-
TIMER->COUNT16.CTRLA.bit.ENABLE = 1; // Enable timer
183-
while(TIMER->COUNT16.SYNCBUSY.bit.ENABLE); // Wait for it
148+
voicePitch(1.0); // Set timer interval & callback
184149

185150
return true; // Success
186151
}
@@ -196,14 +161,15 @@ bool voiceSetup(bool modEnable) {
196161
// adjustment (after appying constraints) will be returned.
197162
float voicePitch(float p) {
198163
float desiredPlaybackRate = sampleRate * p;
199-
int32_t period = (int32_t)(48000000.0 / desiredPlaybackRate + 0.5);
200-
if(period > 2500) period = 2500; // Hard limit is 65536, 2.5K is a practical limit
201-
else if(period < 250) period = 250; // Leave some cycles for IRQ handler
202-
TIMER->COUNT16.CC[0].reg = period - 1;
203-
while(TIMER->COUNT16.SYNCBUSY.bit.CC0);
204-
float actualPlaybackRate = 48000000.0 / (float)period;
164+
int32_t period = (int32_t)(48000000.0 / 16.0 / desiredPlaybackRate + 0.5);
165+
if(period > 160) period = 160; // Hard limit is 65536, 160 is a practical limit
166+
else if(period < 16) period = 16; // Leave some cycles for IRQ handler
167+
float actualPlaybackRate = 48000000.0 / 16.0 / (float)period;
205168
p = (actualPlaybackRate / sampleRate); // New pitch
206169
jumpThreshold = (int)(jump * p + 0.5);
170+
171+
arcada.timerCallback((int)actualPlaybackRate, playCallback);
172+
207173
return p;
208174
}
209175

@@ -223,9 +189,11 @@ void voiceGain(float g) {
223189
void voiceMod(uint32_t freq, uint8_t waveform) {
224190
if(modBuf) { // Ignore if no modulation buffer allocated
225191
if(freq < MOD_MIN) freq = MOD_MIN;
192+
/*
226193
uint16_t period = TIMER->COUNT16.CC[0].reg + 1; // Audio out timer ticks
227-
float playbackRate = 48000000.0 / (float)period; // Audio out samples/sec
194+
float playbackRate = 48000000.0 / 16.0 / (float)period; // Audio out samples/sec
228195
modLen = (int)(playbackRate / freq + 0.5);
196+
*/
229197
if(modLen < 2) modLen = 2;
230198
if(waveform > 4) waveform = 4;
231199
modWave = waveform;
@@ -397,10 +365,8 @@ void PDM_SERCOM_HANDLER(void) {
397365
evenWord ^= 1;
398366
}
399367

400-
// Playback timer interrupt
401-
void TIMER_IRQ_HANDLER(void) {
402-
TIMER->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF;
403-
368+
// Playback timer callback
369+
static void playCallback(void) {
404370
// Modulation is done on the output (rather than the input) because
405371
// pitch-shifting modulated input would cause weird waveform
406372
// discontinuities. This does require recalculating the modulation table

0 commit comments

Comments
 (0)