Hearing I2C Transmission In Audio Output? (Teensy 4.1/3.6)

Status
Not open for further replies.
Hi all,

I'm working with a setup atm that involves sending I2C from a teensy 4.1 to a 3.6. The 4.1 is running the audio library out to an external DAC (CS4344) and these are working fine together (I'm just running a 100Hz sine out for now). The 3.6 is displaying incoming messages from the 4.1 on a TFT display. This also works great in terms of how the 3.6 is receiving and how the visuals are displaying. There's a button hooked up to the 4.1 that controls when an I2C message is sent - that's also working fine.

The issue is that whenever the 4.1 sends an i2c message, the audio output gets interrupted by some harsh noise. I got this up on a scope and it looks like the I2C signal is somehow bleeding into the audio output? Has anyone had any experience with this before?

I'm using pins 18 and 19 as SDA and SCL, respectively. I understand that the audio library can use these for configuring the audio board, but as I'm using an external dac, I'm not using the SGTL5000 object - which I assumed would mean I wouldn't have to worry about that issue. I could be assuming wrong though! haha

Thanks in advance :)
 
Just a quick update for anyone who might find this thread down the line. I've switched to UART now and, with a baud rate of 9600, everything seems to work ok. Faster baud rates can cause similar issues to what I was getting with I2C, though. Still don't entirely understand the cause of the issue, but if anyone more experienced than me ever has a theory/answer, I'd love to know! :cool:
 
Circuit, code. Otherwise we've no information. This could easily be either hardware or software problem from the description,
so both are needed.
 
It less likely the noise is getting from the I2C stream into the I2C stream (digitally) due to SW bug. It's probably more likely the noise is coupling from the digital circuits into the analog circuits.

Some things you can try to reduce EMI interference:
- put series 100 ohm resistors on your I2C lines near the I2C slave and 33 ohm series resistors on the I2S lines.
- reduce the drive strength on the I/O. By default I think they are at max strength/slew (and hence max EMI emission due to faster edges)
- create a dedicated analog supply for your analog circuits, don't feed them with the same supply as the digital circuits to prevent noise on the digital supply directly coupling into analog signals
 
For reference, here's a pic of the circuit I was using (no schematic sorry!), with the caveat that I was using the i2c outputs from pins 24 and 25 on the teensy 4.1 (top), running into pins 18 and 19 on the 3.6 (bottom).

photo_2021-03-08_17-07-48.jpg

After a little bit of testing before I switched to UART, my guess is that @Blackaddr is probably right that this is an EMI issue. Probably something to do with the breadboard, seeing as even with UART the higher baud rates were causing the same problem. I was told the other day that breadboards can have these sorts of issues with faster digital signals, so it wouldn't surprise me if that was the issue I was running into.

Re: Code, I'm pretty sure this is what I was using but due to a few different reasons I'm not able to test the sketches on the teensy at the moment, so can't confirm:

Sender:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <avr/io.h>
#include <avr/interrupt.h>


// GUItool: begin automatically generated code
AudioSynthWaveform       waveform1;      //xy=187,128
AudioOutputI2S           dacs1;          //xy=589,157
AudioConnection          patchCord1(waveform1, 0, dacs1, 0);
AudioConnection          patchCord2(waveform1, 0, dacs1, 1);
// GUItool: end automatically generated code
//
byte wavetableX[128];
byte wavetableY[128];
byte waveOut[128];
byte counter;
byte buttonPin = 9;
unsigned long currentMils, startMils, startMils2;
byte loopCount = 0;

void setup() {
  Wire2.begin();
  Serial.begin(9600);
  while (!Serial) ;
  delay(3000);

  pinMode(buttonPin, INPUT_PULLUP);
  
  AudioMemory(10);
  waveform1.begin(1.0, 50.0, WAVEFORM_SINE);
  startMils = millis();
}

void loop() {
  currentMils = millis();
  if (currentMils - startMils >= 100)  
  {
      onPress();
  }
}

void transmit(byte data){
      Wire2.beginTransmission(0x0A);
      Wire2.write(data); //Writes byte by byte
      Wire2.endTransmission();
}

void onPress(){
  byte mult = byte(random(1, 5));
  for(int i = 0; i < 128; i++){  
    wavetableY[i] = map(sin(2*PI*(i*mult)/128), -1, 1, 1, 127);
    //Serial.println(wavetableX[i]);
    transmit(wavetableY[i]);
  }  
}

Receiver:
Code:
// This Teensy3 and 4 native optimized and extended version
// requires specific pins. 
// If you use the short version of the constructor and the DC
// pin is hardware CS pin, then it will be slower.

#define TFT_MISO  12
#define TFT_MOSI  11  //a12
#define TFT_SCK   13  //a13
#define TFT_DC   9 
#define TFT_CS   10  
#define TFT_RST  8

//----------------------------
//ADAFRUIT COLOUR LIST//
// Color definitions
#define BLK    0x0000
#define BLUE     0x001F
#define RED      0xF800
#define GREEN    0x07E0
#define CYAN     0x07FF
#define MAGENTA  0xF81F
#define YELLOW   0xFFE0 
#define WHT    0xFFFF
//-----------------------------

// Note the above pins are for the SPI object.  For those Teensy boards which have
// more than one SPI object, such as T3.5, T3.6, T4 which have at SPI1 and SPI2
// LC with SPI1, look at the cards that come with the teensy or the web page
// https://www.pjrc.com/teensy/pinout.html to select the appropriate IO pins.

//#include <Adafruit_GFX.h>    // Core graphics library
#include <ST7735_t3.h> // Hardware-specific library
#include <ST7789_t3.h> // Hardware-specific library
#include <SPI.h>
#include <Wire.h>

ST7735_t3 tft = ST7735_t3(TFT_CS, TFT_DC, TFT_RST);

#define MISO1 1
#define MOSI1 0
#define SCLK 32
#define CS 31

float p = 3.1415926;
byte outArray[128];
unsigned long currentMils, startMils, startMils2;
int period = 50;
int reader;
byte upper, lower;
byte counter;

void setup(void) {
  Wire.begin(42);              // join i2c bus with address #80
  Wire.onReceive(receiveEvent); // register event
   
  //pinMode(SD_CS, INPUT_PULLUP);  // don't touch the SD card
  pinMode(A13, INPUT);
  pinMode(A12, INPUT);

  // Or use this initializer (uncomment) if you're using a 1.44" TFT (128x128)
  tft.initR(INITR_144GREENTAB);

  tft.setRowColStart(4,2);

  //Serial.println("init");

  uint16_t time = millis();
  tft.fillScreen(ST7735_BLACK);
  time = millis() - time;

  //Serial.println(time, DEC);
  delay(500);

  tft.fillScreen(ST7735_BLACK);


  clearOutArray();
  updateScope();
  startMils = startMils2 = millis();
}

void loop() {
  currentMils = millis();
  if (currentMils - startMils >= period)  
  {
    updateScope();
    startMils = currentMils;  
  }
}

void clearOutArray(){
  for(int x = 0; x < 128; x++){
      outArray[x] = 64;  
  }
}

void updateScope(){
  tft.fillScreen(ST7735_BLACK);
  for(int x = 0; x < tft.width(); x++){
      tft.drawPixel(x, outArray[x], RED);  
  }
}

void receiveEvent(){
//I2C---------------------------------------------------------
  while(Wire.available()) // loop through all but the last
  {
    byte c = Wire.read(); // receive byte 
    outArray[counter] = c;
    counter++;
    if(counter > 127){counter = 0;}
  }

  Wire.requestFrom(80, 1);
  while(Wire.available()) {
    Serial.println("!");
  }  
}

Regardless - I'm able to do everything I need to with UART now, so this is by no means urgent for me or needs a definite solution right now. Just wanted to post this in case anyone else runs into a similar issue :)
 
Status
Not open for further replies.
Back
Top