(Solved) Teensy 3.2 with audio, serial, and ili9341 touchscreen hangup problem
Hey All,
System Overview: Teensy 3.2 connected to SGTL5000, ili9341 touch screen display, and RS-485 on TX1/RX1 for audio retrieval and playback
Problem: Hang up of audio library when calling XXX.getBuffer(); from a playqueue object. Processor hangs up approximately 7 to 10 minutes after power up on the .getbuffer() call. Line 255 of the code below.
Elaboration:
Audio packets come into RS-485 and pushed to audio library for playback. Audio packets come from a remote Teensy 3.2.
The code below fails when calling audio_queue.getBuffer(). Checked this is the hangup point with a scope, as I used the RS-485 direction pin as a visual feedback before and after the function call.
Other indications: about 30 seconds before the failure, there is a spike and subsequent return to normal of audio library CPU usage. After the ~30 seconds, memory usage starts ramping up over 5-10 seconds from the nominal 2/3 blocks to the max audiomemory allocated; system hangs up indicated by a buzzing noise since no more audio packets are pushed into playqueue, and the controller resets due to a watchdog time out.
Troubleshooting efforts:
changing audio memory allocation (tried 4, 8, 12, 20) doesn't change outcome.
Removing the LCD touchscreen routines in loop doesn't change outcome.
Adding delay in loop seemed to improve outcome, except a failure was noted after 26 minutes.
The other teensy which sends the audio packets has never failed and has a similar, albeit less strenuous, interrupt routine to check for audio packets and spit them out over RS-485. The other teensy also doesn't connect to a touch screen or any other peripherals besides the recording SGTL5000.
Code:
Any help is greatly appreciated
Hey All,
System Overview: Teensy 3.2 connected to SGTL5000, ili9341 touch screen display, and RS-485 on TX1/RX1 for audio retrieval and playback
Problem: Hang up of audio library when calling XXX.getBuffer(); from a playqueue object. Processor hangs up approximately 7 to 10 minutes after power up on the .getbuffer() call. Line 255 of the code below.
Elaboration:
Audio packets come into RS-485 and pushed to audio library for playback. Audio packets come from a remote Teensy 3.2.
The code below fails when calling audio_queue.getBuffer(). Checked this is the hangup point with a scope, as I used the RS-485 direction pin as a visual feedback before and after the function call.
Other indications: about 30 seconds before the failure, there is a spike and subsequent return to normal of audio library CPU usage. After the ~30 seconds, memory usage starts ramping up over 5-10 seconds from the nominal 2/3 blocks to the max audiomemory allocated; system hangs up indicated by a buzzing noise since no more audio packets are pushed into playqueue, and the controller resets due to a watchdog time out.
Troubleshooting efforts:
changing audio memory allocation (tried 4, 8, 12, 20) doesn't change outcome.
Removing the LCD touchscreen routines in loop doesn't change outcome.
Adding delay in loop seemed to improve outcome, except a failure was noted after 26 minutes.
The other teensy which sends the audio packets has never failed and has a similar, albeit less strenuous, interrupt routine to check for audio packets and spit them out over RS-485. The other teensy also doesn't connect to a touch screen or any other peripherals besides the recording SGTL5000.
Code:
Code:
/*
Special Notes:
noteFreq library must be modified to reduce calculation time.
[ Located in analyze_notefreq.h ]
#define AUDIO_GUITARTUNER_BLOCKS 6
serial buffer size is considerably larger to accomodate audio data transfer.
[ Located in Serial1.c ]
#define TX_BUFFER_SIZE 512 // number of outgoing bytes to buffer
#define RX_BUFFER_SIZE 512 // number of incoming bytes to buffer
To do:
implement notes about the RGB 565 encoding of the ILI9341
in the bit compressed format, the Red is 5 MSB's, green is the next 6 bits, and blue is 5 remaining the LSB's
of a 16 bit string
setup some bidirectional traffic
need to figure out if a collision will ever happen when switching UART modes
*/
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <ILI9341_t3.h>
#include <font_Arial.h> // from ILI9341_t3
#include <XPT2046_Touchscreen.h>
#include "enums.h"
// GUItool: begin automatically generated code
AudioPlayQueue audio_queue; //xy=307,242
AudioOutputI2S i2s1; //xy=436,173
AudioConnection patchCord1(audio_queue, 0, i2s1, 0);
AudioConnection patchCord2(audio_queue, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=387,310
// GUItool: end automatically generated code
//Setup the WatchDog Timer
#ifdef __cplusplus
extern "C" {
#endif
void startup_early_hook() {
//top value when counting at 200hz rate
WDOG_TOVALL = 1600;
//bottom value
WDOG_TOVALH = 0;
//start watchdog
WDOG_STCTRLH = (WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN | WDOG_STCTRLH_STOPEN);
}
#ifdef __cplusplus
}
#endif
// For optimized ILI9341_t3 library
#define CS_PIN 8
#define TFT_DC 20
#define TFT_CS 21
#define TFT_RST 255 // 255 = unused, connect to 3.3V
#define TFT_MOSI 7
#define TFT_SCLK 14
#define TFT_MISO 12
#define LCD_light A2
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN 2
//XPT2046_Touchscreen ts(CS_PIN); // Param 2 - NULL - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, 255); // Param 2 - 255 - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling
#define x_touch_max 3800
#define x_touch_min 150
#define y_touch_max 4000
#define y_touch_min 130
#define screen_width 320
#define screen_height 240
const double x_scale = (double)screen_width / (double)(x_touch_max - x_touch_min);
const double y_scale = (double)screen_height / (double)(y_touch_max - y_touch_min);
const int standard_color_default[17][4] = {
// R G B W
{ 0, 0, 0, 0}, //no color
{255, 0, 0, 0}, //red
{255,100, 0, 0}, //orange
{255,255, 0, 0}, //yellow
{100,255, 0, 0}, //yellow green
{ 0,255, 0, 0}, //green
{ 0,255,100, 0}, //ocean green
{ 0,255,255, 0}, //cyan
{ 0,100,255, 0}, //sky blue
{ 0, 0,255, 0}, //blue
{100, 0,255, 0}, //purple
{255, 0,255, 0}, //magenta
{255, 0,100, 0}, //pink
{ 0, 0, 0,255}, //white
{255, 0, 0,100}, //light red
{ 0,255, 0,100}, //light green
{ 0, 0,255,100}, //light blue
};
int button_array[20][5];
int active_preset = 1;
int color_to_correct = magenta;
int vector_origin_color = red;
int vector_one_color = green;
int vector_two_color = blue;
int vector_three_color = white;
int standard_color[17][4];
int previous_menu = title_screen;
uint32_t watchdog_current_time;
uint32_t watchdog_dog_timer = 0;
//serial communication constants for audio transfer stuff
/*
Time(uS)
Point P1 p2 p3 p4 p5 p6 p7
| | | | | | |
| | | | | | period of wait
| | | | | violin reads
| | | | user finishes transmittal
| | | user starts transmital
| | violin turns off transmitter
| violin finishes last byte
violin starts byte 0 transmission
P1 - Violin Starts transmitting data
P2 - Calculated or observed Violin Transmit Time finishes
P3 - Violin turns to transmitter after transmit finished
P4 - User should transition to transmitter a fixed time after last byte received
P5 - User Finishes transmission and turns back to receiver
P6 - Violin Reads the incoming bytes delay
*/
#define check_status_of_trigger_delay 100 //check for arrival of data every 100uS (short routine)
#define transceiver_mode_switch_delay 5 //arbitrary, could be as low as 1uS
#define serial1_speed 1400000 //slowest baud rate without collisions
#define violin_receive_after_transmission 1950 //violin time
#define user_final_receive_to_transmit_delay 200 //user
#define user_transmit_finished 100 //user
#define violin_read_delay 300 //violin time
#define audio_packet_length 256 //audio packets are 16 bit 128 samples wide, thus 256 bytes
#define extra_bytes 4
#define audio_message_length 260 //sum of audio_packet_length and extra_bytes
#define transmit_enable_pin 4
byte receive_buffer[4];
IntervalTimer myTimer;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Initialization //
/////////////////////////////////////////////////////////////////////////////////////////////////////
void setup(){
//Start up communication with computer
Serial.begin(250000);
delay(1);
//Start up communication with external teensy
Serial1.begin(serial1_speed);
pinMode(transmit_enable_pin,OUTPUT);
digitalWrite(transmit_enable_pin,LOW);
delayMicroseconds(transceiver_mode_switch_delay);
//Setup Audio Memory
// Inventory of Objects using memory
// Output Audio - 2 blocks when writing a packet and another arrives
// Buffer for lockup safety - 8 blocks
AudioMemory(10);
//SGTL
// Turn on the device and set to appropriate volume level.
sgtl5000_1.enable();
sgtl5000_1.volume(0.8);
delay(1);
//start checking for audio packets
myTimer.begin(receive_audio, check_status_of_trigger_delay);
//setup the touchscreen device
pinMode(LCD_light, OUTPUT);
digitalWrite(LCD_light, HIGH); //turn on back light
tft.begin();
tft.setRotation(1);
tft.fillScreen(ILI9341_BLACK);
ts.begin();
redisplay(title_screen);
load_standard_colors();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Primary Interrupt Delay Routines //
/////////////////////////////////////////////////////////////////////////////////////////////////////
void receive_audio(){
//ensure RS-485 is in receive mode
digitalWrite(transmit_enable_pin,LOW);
//check if samples are available
int bytes_available = Serial1.available();
if(bytes_available > 0){
myTimer.end();
uint32_t current_time = micros();
boolean toss_sample = false;
int bytes_previously_available = bytes_available;
//wait for packet of fixed length to arrive, time out if middle of packet
while(bytes_available < audio_message_length){
//how many bytes do I have now?
bytes_available = Serial1.available();
//if more bytes have arrived, reset timeout
if(bytes_available > bytes_previously_available){
bytes_previously_available = bytes_available;
current_time = micros();
}
//check for timeout, if timeout then flush and break
uint32_t time_out = micros() - current_time;
if(time_out > 100){
toss_sample = true;
Serial1.clear();
myTimer.begin(receive_audio, check_status_of_trigger_delay);
break;
}
}
//If total amount of samples received in appropriate time
if(toss_sample == false){
//kick off transmit timer
//the code below SHOULD finish before this interrupt gets called
myTimer.begin(transmit_data, user_final_receive_to_transmit_delay);
//capture all data in respective buffers
byte sample_buffer[audio_packet_length];
for(int i = 0; i < audio_packet_length; i++){
sample_buffer[i] = Serial1.read();
}
for(int i = 0; i < extra_bytes; i++){
receive_buffer[i] = Serial1.read();
}
//pass the audio data out to the SGTL Audio Chip
int16_t *audioBuffer = audio_queue.getBuffer();
if (audioBuffer != NULL){
memcpy(audioBuffer, sample_buffer, audio_packet_length);
audio_queue.playBuffer();
//audio_queue.update();
}
}
}
//Sevice the Watch Dog
watchdog_current_time = millis();
if((watchdog_current_time - watchdog_dog_timer) > 100){
noInterrupts();
WDOG_REFRESH = 0xA602;
WDOG_REFRESH = 0xB480;
interrupts();
watchdog_dog_timer = millis();
}
}
void transmit_data(){
//dont get interrupted by self
myTimer.end();
digitalWrite(transmit_enable_pin,HIGH);
delayMicroseconds(transceiver_mode_switch_delay);
//write data
byte send_buffer[4];
send_buffer[0] = 1;
send_buffer[1] = 2;
send_buffer[2] = 3;
send_buffer[3] = 4;
Serial1.write(send_buffer,4);
//delay for a little until transmission on its way
delayMicroseconds(user_transmit_finished);
digitalWrite(transmit_enable_pin,LOW);
delayMicroseconds(transceiver_mode_switch_delay);
//reset timer to check for next serial event
myTimer.begin(receive_audio, check_status_of_trigger_delay);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// User Non-time sensitve functions //
/////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
boolean istouched = ts.touched();
for(int i = 0; i<1000; i++){
istouched = ts.touched();
delayMicroseconds(5);
}
if (istouched) {
//delay to allow a proper finger press on the screen
delay(60);
//collect touch point and average over some samples
int x_raw = 0;
int y_raw = 0;
int z_raw = 0;
int average_samples = 5;
int press_threshold = 1500; //of 4000
TS_Point p = ts.getPoint();
for(int i = 0; i<average_samples; i++){
x_raw = p.x + x_raw;
y_raw = p.y + y_raw;
z_raw = p.z + z_raw;
p = ts.getPoint();
delay(10);
}
x_raw = x_raw / average_samples;
y_raw = y_raw / average_samples;
z_raw = z_raw / average_samples;
//only permit high pressure press events through
if(z_raw > press_threshold){
//convert the raw touch screen input to 320x240 display coordinate
int x_conv = (int)((x_touch_max - x_raw) * x_scale);
int y_conv = (int)((y_touch_max - y_raw) * y_scale);
//print some debug information
//serial_print_touch_screen_position(x_raw,y_raw,z_raw,x_conv,y_conv);
//draw the button press location for debug purposes
draw_button_press_location(x_conv,y_conv);
//check the position against button matrix
int action_to_take = check_button_position_array(x_conv,y_conv);
//Serial.println(action_to_take);
//take update action
//value of 100 is take no action
int update_screen = take_action_return_new_screen(action_to_take);
//delay the input and then redraw the display
delay(50);
redisplay(update_screen);
delay(250);
}
}
report_audio_stats();
}
Any help is greatly appreciated
Last edited: