got stutter fixed
This commit is contained in:
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user