Hello, I'm working on a school project using the Teensy 4.0 and audio board for a real-time audio project that uses encoders and a standard 4x20 LCD using the PCF8574 to control the LCD with the LiquidCrystal_I2C library by YWROBOT for the user interface.
I've been working on creating the GUI for this project and tried using the IntervalTimer library as a way to generate the refresh interrupt for the LCD, but I've quickly ran into the problem of the audio cutting out at whatever interval I set the timer to. I have been trying to mess around with the priority of the interval in reference to the update function for the audio library, but I can't seem to get the audio not to glitch.
The Teensy 4.0 is a very capable device and I've seen projects involving much larger LCDs in conjunction with much higher refresh rates than i'm using so I'm sure my approach to doing this is just incorrect. I am not sure though if it is my choice in LCD library or method of generating the refresh interrupt or something else that is causing me problems. I'm also more generally trying to understand a good approach to designing an interactive system while using the audio library.
Attached below is my simple test that updates a value on the LCD at a given refresh rate while just passing the audio through some buffers. I greatly appreciate any insight!
I've been working on creating the GUI for this project and tried using the IntervalTimer library as a way to generate the refresh interrupt for the LCD, but I've quickly ran into the problem of the audio cutting out at whatever interval I set the timer to. I have been trying to mess around with the priority of the interval in reference to the update function for the audio library, but I can't seem to get the audio not to glitch.
The Teensy 4.0 is a very capable device and I've seen projects involving much larger LCDs in conjunction with much higher refresh rates than i'm using so I'm sure my approach to doing this is just incorrect. I am not sure though if it is my choice in LCD library or method of generating the refresh interrupt or something else that is causing me problems. I'm also more generally trying to understand a good approach to designing an interactive system while using the audio library.
Attached below is my simple test that updates a value on the LCD at a given refresh rate while just passing the audio through some buffers. I greatly appreciate any insight!
Code:
#include <Audio.h>
#include <stdio.h>
#include <LiquidCrystal_I2C.h> //YWROBOT
#include <IntervalTimer.h>
#define AUDIO_MASK 0x0000FFFF
#define NUM_BLOCKS 8
#define CIRCULAR_BUFFER_LENGTH AUDIO_BLOCK_SAMPLES * NUM_BLOCKS
#define CIRCULAR_BUFFER_MASK (CIRCULAR_BUFFER_LENGTH - 1)
#define MAX_SAMPLE_BLOCKS NUM_BLOCKS - 1
//Audio library macro, AUDIO_BLOCK_SAMPLES = 128
AudioInputI2S i2s_in;
AudioOutputI2S i2s_out;
AudioRecordQueue Q_in_L;
AudioRecordQueue Q_in_R;
AudioPlayQueue Q_out_L;
AudioPlayQueue Q_out_R;
AudioConnection patchCord1(i2s_in, 0, Q_in_L, 0);
AudioConnection patchCord2(i2s_in, 1, Q_in_R, 0);
AudioConnection patchCord3(Q_out_L, 0, i2s_out, 0);
AudioConnection patchCord4(Q_out_R, 0, i2s_out, 1);
AudioControlSGTL5000 sgtl5000;
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27
IntervalTimer lcdUpdate;
const int myInput = AUDIO_INPUT_LINEIN;
unsigned int curSample = 0;
int curBlock = 0;
// Temperary arrays to hold new values of current sample block
double leftIn[CIRCULAR_BUFFER_LENGTH] = {0.0};
double rightIn[CIRCULAR_BUFFER_LENGTH] = {0.0};
double leftOut[CIRCULAR_BUFFER_LENGTH] = {0.0};
double rightOut[CIRCULAR_BUFFER_LENGTH] = {0.0};
volatile int count = 0;
short *bp_L, *bp_R;
void setup(void)
{
lcd.init();
// Print a message to the LCD.
lcd.backlight();
lcdUpdate.begin(countByOne, 5e5); //lcd refresh rate in usec
lcdUpdate.priority(255);
// Audio connections require memory. and the record queue
// uses this memory to buffer incoming audio.
AudioMemory(10);
// Enable the audio shield. select input. and enable output
sgtl5000.enable();
sgtl5000.inputSelect(myInput);
sgtl5000.volume(0.5);
// Start the record queues
Q_in_L.begin();
Q_in_R.begin();
Serial.begin(9600);
}
void countByOne()
{
unsigned long curTime = millis();
count++;
lcd.clear();
char str[20];
sprintf(str, "Count: %d", count);
lcd.print(str);
unsigned long time = millis() - curTime;
Serial.printf("%lu\n", time);
}
void loop(void)
{
// Wait for left and right input channels to have content
while (!Q_in_L.available() && !Q_in_R.available());
bp_L = Q_in_L.readBuffer();
bp_R = Q_in_R.readBuffer();
int startIndex = curBlock * AUDIO_BLOCK_SAMPLES;
for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
curSample = startIndex + i;
leftIn[curSample] = (double)bp_L[i];
rightIn[curSample] = (double)bp_R[i];
}
Q_in_L.freeBuffer();
Q_in_R.freeBuffer();
// Get pointers to "empty" output buffers
bp_L = Q_out_L.getBuffer();
bp_R = Q_out_R.getBuffer();
// Operate on each value in current block that has been received
for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
curSample = startIndex + i;
leftOut[curSample] = leftIn[curSample];
rightOut[curSample] = rightIn[curSample];
}
// copy the processed data block back to the output
for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
curSample = startIndex + i;
bp_L[i] = (short)leftOut[curSample];
bp_R[i] = (short)rightOut[curSample];
}
curBlock++;
curBlock &= MAX_SAMPLE_BLOCKS;
// and play them back into the audio queues
Q_out_L.playBuffer();
Q_out_R.playBuffer();
}