I2C Serial Menu for ADC/DAC/Codec Driver Development

JayShoe

Well-known member
Hello,

I need some help with my I2C Menu app... I created a new Codec board out of a TLV320AIC3105 chip. It's powered on, and I'm communicating with it via I2C (yay!). I've done this before with a few other chips, and I created an "I2C_menu" app so that I can just send a few I2C commands to the chip. This allows me to confirm that the hardware is working, and confirm the steps involved for initialization of the new chip, so that I can begin to write a driver for it.

The code is as follows.

Code:
/* 
	I2C Menu + Audio
  
  Run this with Serial - Midi - Audio board type.
  (build_flags = -D USB_MIDI_AUDIO_SERIAL)
 
	License: MIT License.  Use at your own risk.
 */


#include <Wire.h>
#include <Audio.h>
#include <SPI.h>
#include <SerialFlash.h>


// GUItool: begin automatically generated code
AudioInputI2S            i2s3;           //xy=190.33333587646484,431.3333930969238
AudioInputUSB            usb1;           //xy=208.3333282470703,498.3333435058594
AudioMixer4              mixer1;         //xy=394.3333549499512,471.3333559036255
AudioOutputI2S           i2s1;           //xy=540.3333015441895,503.33335876464844
AudioConnection          patchCord1(i2s3, 0, mixer1, 2);
AudioConnection          patchCord2(i2s3, 1, mixer1, 3);
AudioConnection          patchCord3(usb1, 0, mixer1, 0);
AudioConnection          patchCord4(usb1, 1, mixer1, 1);
AudioConnection          patchCord5(mixer1, 0, i2s1, 0);
AudioConnection          patchCord6(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=310.3333282470703,613.3333435058594
// GUItool: end automatically generated code


uint8_t currentI2C_addr = 0x18;
int currentPage = 0;

void setup() {
    Serial.println("Setup");
    Serial.println("");
    Serial.println("");
    Serial.println("");
    Serial.println("");
    AudioMemory(100);
  Wire.begin();
  delay(5); // wait for steady I2C line
  Serial.begin(9600);
  Serial.setTimeout(999999);
  delay(1000);
}

void loop() {
    Serial.println("Loop");
  menu();
}

void scanI2C()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    delay(5);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.println("\nI2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("!");

      nDevices++;
    }
    else if (error == 4)
    {
      Serial.print("\nUnknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
    else {
      if (address == 32 || address == 64 || address == 96) {
        Serial.print(".\n");
      } else {
        Serial.print(".");
      }
    }
  }
  if (nDevices == 0)
    Serial.println("\nNo I2C devices found\n");
  else
    Serial.println("done\n");
}

void moveI2C_addr() {
  byte error = 1;
  uint8_t xx;
  xx = inputHexValue(1);
  Serial.print("\nAttempting to switch current I2C address to ");
  PrintHex8(&xx, 1);
  Serial.println();
  Wire.beginTransmission(xx);
  delay(5);
  error = Wire.endTransmission();

  if (error == 0)
  {
    Serial.print("I2C device found at address ");
    PrintHex8(&xx, 1);
    currentI2C_addr = xx;
    Serial.println("!");
  } else {
    Serial.print("Unable to connect to I2C device at address ");
    PrintHex8(&xx, 1);
    Serial.println("!");
    Serial.print("Current I2C address not changed!\n\n\n");
  }

}

uint8_t inputHexValue(int n) {
  //Take the input
  Serial.println("\n\nInput one hex value,");
  Serial.println("i.e. 0x4C");
  Serial.print("Input: ");
  Serial.readStringUntil('\n');
//  Serial.setTimeout(999999);
  String param = Serial.readStringUntil('\n');
  Serial.print(param);

  //Process the results into xx
  char buf[5];
  param.toCharArray(buf, 5);
  uint8_t xx;
  sscanf(buf, " %x", &xx);

  // Print the results
  Serial.println();
  Serial.print("Decimal: "); Serial.print(xx);
  Serial.println();
  Serial.print("Hex: "); PrintHex8(&xx, 1);
  Serial.println();
  return xx;
}

void printResults(uint8_t val) {
  Serial.print("  ");  Serial.print(val);
  Serial.println();
  Serial.print("    Hex: ");  PrintHex8(&val, 1);
  Serial.println();
  Serial.print("    Bin: ");  Serial.println(val,BIN);
}


void readI2C_command() {
  String param;
  uint8_t xx = 0;
  uint8_t yy = 0;
  //accept input
  Serial.println("\nInput the page and register (in hex) you wish to read,");
  Serial.println("i.e. 0x01 0x03");
  Serial.print("\nInput: ");

  if (Serial.available()) {
    Serial.read();
    param = Serial.readStringUntil('\n');
    Serial.println(param);
  }


  //process values
  Serial.println("Process Values");
  char buf[20];
  param.toCharArray(buf, 20);
  sscanf(buf, "%x %x", &xx, &yy);

  //display the results
  Serial.print("Page: "); printResults(xx);
  Serial.print("Reg: "); printResults(yy);

  //Read the value
  readValue(xx, yy);
}

void writeI2C_command() {
  Serial.println("\nInput the page, register, and value (in hex) you wish to write,");
  Serial.println("i.e. 0x01 0x3F 0x00");
  Serial.readStringUntil('\n');
//  Serial.setTimeout(999999);
  Serial.print("\nInput: ");
  String param = Serial.readStringUntil('\n');
  Serial.println(param);

  //process values
  char buf[25];
  param.toCharArray(buf, 25);
  uint8_t xx;
  uint8_t yy;
  uint8_t zz;
  sscanf(buf, "%x %x %x", &xx, &yy, &zz);

  //Print Results
  Serial.print("Page: "); printResults(xx);
  Serial.print("Reg: "); printResults(yy);
  Serial.print("Value: "); printResults(zz);

  // Write Page
  writePage(xx, yy, zz);
}

void dumpAllRegisters() {
  Serial.println("\nDumping all registers...");
  currentPage = 0;
  for (int reg = 1; reg <= 121; reg++) {
    readValue(currentPage, reg);
    delay(2);
  }
  currentPage = 1;
  for (int reg = 1; reg <= 9; reg++) {
    readValue(currentPage, reg);
    delay(2);
  }
}

void readValue(uint8_t page, uint8_t reg) {
  Serial.println("");
  Serial.println("Read Value");
  uint8_t val;
  if (goToPage(page)) {
    Wire.beginTransmission(currentI2C_addr);
    Wire.write(reg);
    uint8_t result = Wire.endTransmission();
    if (result != 0) {
      Serial.print("readValue: ERROR: Read Page.");
      Serial.print(" Page: "); printResults(page);
      Serial.print(" Reg: "); printResults(reg);
      Serial.println(".  Received Error During Read Page: ");
      //val = 300 + result;
      return;
    }
    if (Wire.requestFrom(currentI2C_addr, 1) < 1) {
      Serial.print("readValue: ERROR: Read Page."); 
      Serial.print(" Page: "); printResults(page);
      Serial.print(" Reg: "); printResults(reg);
      Serial.println(".  Nothing to return");
      return;
    }
    if (Wire.available() >= 1) {
      Wire.beginTransmission(currentI2C_addr);
      Serial.println("readValue: Read Value.");
      Serial.print(" Page: "); printResults(page);
      Serial.print(" Reg: "); printResults(reg);
      uint8_t val = Wire.read(); delay(10);
      Serial.print("Received: "); printResults(val);
    Wire.endTransmission(); delay(10);
    return;
    }
    return;
  } 
  else {
    Serial.print("control: INFO: Read Page.  Page: "); Serial.print(page);
    Serial.print(" Reg: "); Serial.print(reg); Serial.print(" ");
    Serial.println(".  Failed to go to read page.  Could not go there.");
    //val = 500;
    return;
  }
  //val = 600;
  Serial.print(val);
  //return val;
}

bool goToPage(byte page) {
  Wire.beginTransmission(currentI2C_addr);
  Wire.write(0x00); delay(10);// page register  //was delay(10) from BPF
  Wire.write(page); delay(10);// go to page   //was delay(10) from BPF
  byte result = Wire.endTransmission();
  if (result != 0) {
    Serial.print("control: Received Error During goToPage(): Error = ");
    Serial.println(result);
    if (result == 2) {
      // failed to transmit address
      //return goToPage(page);
    } else if (result == 3) {
      // failed to transmit data
      //return goToPage(page);
    }
    return false;
  }
  return true;
}

  /*
void transmit_exported_registers(cfg_reg *r, int n) {

  Serial.println("Beginning to transmit exported registers...");
  int i = 0;
  while (i < n) {
    Wire.beginTransmission(currentI2C_addr);
    Serial.print("r[");
    Serial.print(i);
    Serial.print("].command: ");
    // PrintHex8(r[i].command, 1);
    Wire.write(r[i].command); delay(10);
    Serial.print("r[");
    Serial.print(i);
    Serial.print("].param: ");
    Serial.println(r[i].param, HEX);
    Wire.write(r[i].param); delay(10);
    Wire.endTransmission();
    i++;
  }
  Serial.println("Finished transmitting all dumped register values");

}
  */

boolean writePage(uint8_t page, uint8_t reg, uint8_t val) {
  Serial.println("control: Write Page."); 
  Serial.print("Page: "); printResults(page);
  Serial.print("Reg: "); printResults(reg);
  Serial.print("Value: "); printResults(val);
  if (goToPage(page)) {
    Wire.beginTransmission(currentI2C_addr);
    Wire.write(reg); delay(10);
    Wire.write(val); delay(10);
    uint8_t result = Wire.endTransmission();
    if (result == 0) return true;
    else {
      Serial.print("control: Received Error During writePage(): Error = ");
      Serial.println(result);
    }
  }
  readValue(page, reg);
  return false;
}

void printMenu() {
            Serial.flush();
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.println("Test menu:");
  Serial.println("---------------------------------------");
  Serial.print("Current I2C Address: ");
  PrintHex8(&currentI2C_addr, 1);
  Serial.println("(" + String(currentI2C_addr) + ")");
  Serial.println("Available options: ");
  Serial.println("1: Move to different I2C address");
  Serial.println("2: Scan I2C address space");
  Serial.println("3: Dump all registers");
  Serial.println("4: Write all preprogrammed registers");
  Serial.println("5: Dump specific register");
  Serial.println("6: Write specific register");
  Serial.println("---------------------------------------");
  Serial.print("Input: ");
}

void menu() {
  printMenu();
  for (;;) {
    switch (Serial.read()) {

      case '1': {
          Serial.print("1");
          moveI2C_addr();
          printMenu();
          break;
        }

      case '2': {
          Serial.print("2");
          scanI2C();
          printMenu();
          break;
        }

      case '3': {
        Serial.print("3");
          dumpAllRegisters();
          printMenu();
          break;
        }

      case '4': {
        Serial.print("4");
        /*
          transmit_exported_registers(registers, sizeof(registers) / sizeof(registers[0]));
          printMenu();
          break;
          */
        }

      case '5': {
        Serial.print("5");
          readI2C_command();
          printMenu();
          break;
        }

      case '6': {
        Serial.print("6");
          writeI2C_command();
          printMenu();
          break;
        }

      default:
        continue;  // includes the case 'no input'
    }
  }
}

void PrintHex8(uint8_t *data, uint8_t length) // prints 8-bit data in hex with leading zeroes
{
  char tmp[16];
  for (int i = 0; i < length; i++) {
    sprintf(tmp, "0x%.2X", data[i]);
    Serial.print(tmp); Serial.print(" ");
  }
}


When I use case 3, I get a dump of all the registry values. Then at the end, it concludes, and returns to printMenu() and then wait for another serial.read input.

Code:
3
Dumping all registers...

Read Value
readValue: Read Value.
 Page:   0
    Hex: 0x00 
    Bin: 0
 Reg:   1
    Hex: 0x01 
    Bin: 1
Received:   0
    Hex: 0x00 
    Bin: 0

Read Value
readValue: Read Value.
 Page:   0
    Hex: 0x00 
    Bin: 0
 Reg:   2
    Hex: 0x02 
    Bin: 10
Received:   16
    Hex: 0x10 
    Bin: 10000
...

But case 5 (Dump specific register) causes the Teensy 4.0 to crash and then restart (showing "setup" in the serial monitor). It crashes right after the readValue() function. I suspect it has something to do with Serial.readStringUntil() not releasing or something? I can not figure out why the teensy crashes here (see the "Setup" in the text below). Any idea?

Code:
5
Input the page and register (in hex) you wish to read,
i.e. 0x01 0x03

Input: 0x01 0x09
Process Values
Page:   1
    Hex: 0x01 
    Bin: 1
Reg:   9
    Hex: 0x09 
    Bin: 1001

Read Value
readValue: Read Value.
 Page:   1
    Hex: 0x01 
    Bin: 1
 Reg:   9
    Hex: 0x09 
    Bin: 1001
Received:   102
    Hex: 0x66 
    Bin: 1100110
Setup...

PS - Arduino has a known bug not allowing select all and copy of the entire serial monitor so my examples are truncated.

If anyone has any clue why the Teensy is crashing and resetting on "case 5", please help. Thank you!

Jay
 
Back
Top