got stutter fixed

This commit is contained in:
zyphlar
2026-07-04 03:28:13 -07:00
parent 0697c3d6f3
commit a385a156f2
2 changed files with 40 additions and 48 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
{
"permissions": {
"allow": [
"Bash(find /c/Users/Will/apps/mobile -type f -name *)"
"Bash(find /c/Users/Will/apps/mobile -type f -name *)",
"WebSearch"
]
}
}
+38 -47
View File
@@ -207,14 +207,15 @@ uint8_t g_currentTrack = 0;
// Audio DMA buffers — uint16_t PWM duty-cycle values for EasyDMA
static uint16_t g_pwmBuf[2][AUDIO_BUF_SIZE];
volatile bool g_bufReady[2] = {false, false};
volatile bool g_bufReady[2] = {false, false};
uint32_t g_trackDoneMs = 0; // nonzero = millis() deadline after which we stop
uint32_t g_nextReadAddr = 0;
uint32_t g_playEnd = 0;
// Timers
unsigned long g_lastActivity = 0;
#define AUTO_OFF_MS (30UL * 60UL * 1000UL) // 30 min auto-shutoff
#define IDLE_SLEEP_MS (60UL * 1000UL) // 1 min idle → sleep
#define IDLE_SLEEP_MS (10UL * 60UL * 1000UL) // 10 min idle → sleep
// USB connected flag
volatile bool g_usbConnected = false;
@@ -693,8 +694,8 @@ void setupBLE() {
// Software gain: 1=unity, 2=2x, etc. Adjustable via 'u'/'d' serial.
static uint8_t g_audioGain = 1;
// Read PCM from current source into g_pwmBuf[b], applying gain and scaling.
// Pads the tail with silence if fewer than AUDIO_BUF_SIZE bytes remain.
// Read PCM into g_pwmBuf[b], pad tail with silence.
// On the first pure-silence fill (track exhausted), arms the stop timer.
static void audioFillBuf(uint8_t b) {
uint8_t pcm[AUDIO_BUF_SIZE];
uint32_t toRead = 0;
@@ -718,24 +719,23 @@ static void audioFillBuf(uint8_t b) {
g_pwmBuf[b][i] = PWM_SILENCE;
}
g_bufReady[b] = true;
// Arm stop timer on first pure-silence fill (all audio already sent to DMA)
if (toRead == 0 && g_trackDoneMs == 0) {
g_trackDoneMs = millis() + 100; // 100ms > 3 buffer lengths (3 × 32ms)
}
}
// PWM0 ISR — fires every 32 ms (512 samples at 16 kHz).
// Just signals which buffer needs refilling; loop() does the actual I/O.
// ISR just chains buffers — end-of-track is handled entirely in loop()
extern "C" void PWM0_IRQHandler() {
if (NRF_PWM0->EVENTS_SEQEND[0]) {
NRF_PWM0->EVENTS_SEQEND[0] = 0;
if (g_playing) {
g_bufReady[0] = false;
NRF_PWM0->TASKS_SEQSTART[1] = 1; // start buf 1 immediately
}
if (g_playing) { g_bufReady[0] = false; NRF_PWM0->TASKS_SEQSTART[1] = 1; }
}
if (NRF_PWM0->EVENTS_SEQEND[1]) {
NRF_PWM0->EVENTS_SEQEND[1] = 0;
if (g_playing) {
g_bufReady[1] = false;
NRF_PWM0->TASKS_SEQSTART[0] = 1; // start buf 0 immediately
}
if (g_playing) { g_bufReady[1] = false; NRF_PWM0->TASKS_SEQSTART[0] = 1; }
}
}
@@ -801,6 +801,10 @@ void audioStart(uint8_t trackNum) {
g_playEnd = g_nextReadAddr + g_trackLen[trackNum];
#endif
g_trackDoneMs = 0;
g_bufReady[0] = false;
g_bufReady[1] = false;
// Stop DMA cleanly, fill both buffers, restart
NRF_PWM0->TASKS_STOP = 1;
uint32_t t = millis();
@@ -823,6 +827,7 @@ void audioStart(uint8_t trackNum) {
void audioStop() {
g_playing = false;
g_trackDoneMs = 0; // cancel any pending auto-advance
NRF_PWM0->TASKS_STOP = 1;
#ifdef POC_INTERNAL_FLASH
@@ -870,9 +875,9 @@ void buttonsInit() {
uint8_t buttonRead() {
for (uint8_t i = 0; i < NUM_BUTTONS; i++) {
// Buttons pull to ground
if (analogRead(BTN_PINS[i]) < 128) {
if (digitalRead(BTN_PINS[i]) == LOW) {
delay(20); // debounce
if (analogRead(BTN_PINS[i]) < 128) {
if (digitalRead(BTN_PINS[i]) == LOW) {
return i + 1;
}
}
@@ -894,7 +899,7 @@ void enterDeepSleep() {
// Don't sleep if any button is currently LOW — would wake instantly.
// Also catches floating pins that the internal pull-up isn't winning against.
for (uint8_t i = 0; i < NUM_BUTTONS; i++) {
if (analogRead(BTN_PINS[i]) < 128) {
if (digitalRead(BTN_PINS[i]) == LOW) {
g_lastActivity = millis(); // postpone
return;
}
@@ -998,23 +1003,6 @@ void setup() {
// Audio
audioInit();
#ifdef POC_INTERNAL_FLASH
if (g_numTracks > 0) {
Serial.println("Diag: playing track0 for 3s...");
audioStart(0);
uint32_t diagEnd = millis() + 3000;
while (millis() < diagEnd && g_playing) {
for (uint8_t b = 0; b < 2; b++) {
if (!g_bufReady[b] && g_nextReadAddr < g_playEnd) {
audioFillBuf(b);
}
}
}
audioStop();
Serial.println("Diag done");
}
#endif
// USB Mass Storage
#ifndef POC_INTERNAL_FLASH
usb_msc.setID("BabyMobile", "Audio Drive", "2.0");
@@ -1191,21 +1179,22 @@ void loop() {
serUploadTick();
#endif
// ---- Refill audio buffers (ISR sets g_bufReady[b]=false when buffer done) ----
// ---- Refill audio buffers ----
if (g_playing) {
for (uint8_t b = 0; b < 2; b++) {
if (!g_bufReady[b] && g_nextReadAddr < g_playEnd) {
audioFillBuf(b);
}
if (!g_bufReady[b]) audioFillBuf(b);
}
}
// Track finished — both buffers drained and no data left
if (!g_bufReady[0] && !g_bufReady[1] && g_nextReadAddr >= g_playEnd) {
audioStop();
if (g_numTracks > 0) {
g_currentTrack = (g_currentTrack + 1) % g_numTracks;
audioStart(g_currentTrack);
}
// ---- End of track: timer-based stop ----
// g_trackDoneMs is armed 100ms after first silence fill.
// By then both DMA buffers have definitely cycled through silence.
if (g_playing && g_trackDoneMs != 0 && millis() >= g_trackDoneMs) {
g_trackDoneMs = 0;
audioStop();
if (g_numTracks > 0) {
g_currentTrack = (g_currentTrack + 1) % g_numTracks;
audioStart(g_currentTrack);
}
}
@@ -1217,18 +1206,20 @@ void loop() {
btnLastMs[btn] = millis();
Serial.print("BTN"); Serial.println(btn);
g_lastActivity = millis();
/*
switch (btn) {
case 1: // Play / Pause
case 2:
case 3:
case 4:
case 5:
if (g_playing) {
audioStop();
} else if (g_numTracks > 0) {
audioStart(g_currentTrack);
}
break;
/*
case 4: // Next track
if (g_numTracks > 0) {
g_currentTrack = (g_currentTrack + 1) % g_numTracks;
@@ -1242,7 +1233,7 @@ void loop() {
if (g_playing) { audioStop(); audioStart(g_currentTrack); }
}
break;
*/
case 6: // Motor toggle
if (g_motorOn) motorStop(); else motorStart(g_motorSpeed);
break;
@@ -1266,7 +1257,7 @@ void loop() {
audioStop();
motorStop();
break;
}*/
}
waitButtonRelease(btn);
}