CS4272 issues

Status
Not open for further replies.

packetloss69

New member
Hi PJRC forum. I hope some of the info listed below will help anyone else trying to get the SuperAudioBoard going under Windows.

Being dumb, it took me quite a while to get this far..

Issues had:
1. Sine generator not providing accurate frequency.
2. Distorted Audio


Sample sketch based on Whollender github example.
Creates a 1KHz sine wave on analogue output as well as sending to PC via USB.

Code:
// Example Sketch using the SuperAudioBoard with the Teensy Audio library
// RF William Hollender (2015)

// This file is public domain

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

// GUItool: begin automatically generated code
AudioInputUSB            usb1;           //xy=236,101
AudioOutputUSB           usb2;           // To PC
AudioSynthWaveformSine   sine1;          //xy=185.09091186523438,194.09091186523438
AudioOutputI2Sslave      i2s1;            //xy=376.0909118652344,219.09091186523438
AudioConnection          patchCord1(sine1, 0, i2s1, 0);
AudioConnection          patchCord2(sine1, 0, i2s1, 1);
AudioConnection          patchCord3(sine1, 0, usb2, 0);
AudioConnection          patchCord4(sine1, 0, usb2, 1);

AudioControlCS4272       AudioBoard;
// GUItool: end automatically generated code

#define CS4272_ADDR 0x10

// This is the actual sample rate with the SuperAudioBoard
#define ACTUAL_SAMPLE_RATE 48000

void setup() {
 // put your setup code here, to run once:
 AudioMemory(20);
 AudioBoard.enable();
 // AudioBoard.enableDither();
  
 // Register 0x1 DAC Digital Interface Format (Bits 2:0)
 // Usinge I2S, up to 24-bit data
 Wire.beginTransmission(CS4272_ADDR);
 Wire.write(1);  // Write to Register 0x1 as on page 38
 Wire.write(B00101001);  // See datasheet Page 38 Table 8.1
 Wire.endTransmission(); 
  

  // Want to set a frequency of 1kHz, but need to account for the difference
  // between the sample rate assumed by the library object (AUDIO_SAMPLE_RATE_EXACT)
  // and the actual sample rate.
  sine1.frequency(1000 * AUDIO_SAMPLE_RATE_EXACT / ACTUAL_SAMPLE_RATE);
  //sine1.frequency(1000);
  sine1.amplitude(0.7);
 
}

void loop() {
  // put your main code here, to run repeatedly:
// Read back audioboard settings
/*
Serial.print("New Loop: ");
Serial.print(AUDIO_SAMPLE_RATE_EXACT);
Serial.println(millis());

  for(unsigned int i = 1; i < 9; i++)
  {
    Wire.beginTransmission(CS4272_ADDR);
    Wire.write(i);
    int ii = Wire.endTransmission();
    if(ii != 0)
    {
      Serial.println("Error in end transmission:");
      Serial.println(ii);
      break;
    }
    if(Wire.requestFrom(CS4272_ADDR,1) < 1)
    {
      Serial.println("Error in request from");
      break;
    }
    Serial.print(i);
    Serial.print(" ");
    Serial.println(Wire.read());
  } 

  delay(5000); */
}

Sine output was ok on output, but with mid-cycle cuts and distortion. Seemed like a timing issue.

I used a Teensy 3.2 @ 96MHz
Teensyduino 1.8.5

To get i2s to play nice on 48KHz i had to modify

File: output_i2s.cpp
Code:
#if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
  // PLL is at 96 MHz in these modes
  -- #define MCLK_MULT 2
  -- # define MCLK_DIV  17
  ++ #define MCLK_MULT 16
  ++ #define MCLK_DIV  125

This provided a clock of exactly 48KHz for i2s
Sine wave frequency was now 1kHz exactly on analogue outputs.


Windows sound did not enjoy the 1KHz sine input.
Input was 48KHz sampled, but delivered via 44.1KHz
This caused mid-cycle distotion as well as a frequency offset etc.
Did not sound right at all.

Had to modify the following to get windows to use it as a 48KHz recording / playback source.

usb_desc.c
Had to replace both occurrences of
Code:
--LSB(44100), MSB(44100), 0,
++LSB(48000), MSB(48000), 0,

usb_audio.cpp
Code:
// Called from the USB interrupt when ready to transmit another
// isochronous packet.  If we place data into the transmit buffer,
// the return is the number of bytes.  Otherwise, return 0 means
// no data to transmit
unsigned int usb_audio_transmit_callback(void)
{
	static uint32_t count=5;
	uint32_t avail, num, target = 48, offset, len=0;
	audio_block_t *left, *right;
  /*
	if (++count < 9) {   // TODO: dynamic adjust to match USB rate
		target = 44;
	} else {
		count = 0;
		target = 45;
	} */

	while (len < target) {
		num = target - len;
		left = AudioOutputUSB::left_1st;
		if (left == NULL) {
			// buffer underrun - PC is consuming too quickly
			memset(usb_audio_transmit_buffer + len, 0, num * 4);
			//serial_print("%");
			break;
		}
		right = AudioOutputUSB::right_1st;
		offset = AudioOutputUSB::offset_1st;

		avail = AUDIO_BLOCK_SAMPLES - offset;
		if (num > avail) num = avail;

		copy_from_buffers((uint32_t *)usb_audio_transmit_buffer + len,
			left->data + offset, right->data + offset, num);
		len += num;
		offset += num;
		if (offset >= AUDIO_BLOCK_SAMPLES) {
			AudioStream::release(left);
			AudioStream::release(right);
			AudioOutputUSB::left_1st = AudioOutputUSB::left_2nd;
			AudioOutputUSB::left_2nd = NULL;
			AudioOutputUSB::right_1st = AudioOutputUSB::right_2nd;
			AudioOutputUSB::right_2nd = NULL;
			AudioOutputUSB::offset_1st = 0;
		} else {
			AudioOutputUSB::offset_1st = offset;
		}
	}
	return target * 4;
}


usb_desc.h
Code:
-- #define AUDIO_TX_SIZE           180 // 44.1 KHz
-- #define AUDIO_RX_SIZE           180 // 44.1 KHz
++ #define AUDIO_TX_SIZE         192 // 48 KHz
++ #define AUDIO_RX_SIZE         192 // 48 KHz

usb_dev.c
Code:
case 0x81A2: // GET_CUR (wValue=0, wIndex=interface, wLength=len)
		if (setup.wLength >= 3) {
			//reply_buffer[0] = 44100 & 255;
			//reply_buffer[1] = 44100 >> 8;
			reply_buffer[0] = 48000 & 255;
			reply_buffer[1] = 48000 >> 8;
			reply_buffer[2] = 0;
			datalen = 3;
			data = reply_buffer;
		} else {
			endpoint0_stall();
			return;
		}
		break;
#endif

Had to uninstall windows Teensy audio driver and re-install to get access to 48KHz version for some reason.
Testing Analog input > usb next.

1kHz.PNG
 
Last edited:
Hi!

could someone do me a favor and share a known-working version of the sine test for the CS4272?

I'm bit confused by the various versions that float around, some using AudioOutputI2Sslave, others usw AudioOutputI2S32bitslave. It's unclear to me whether or not the Superaudioboard is supported out of the box by now? (Judging from above sketch, no?)

Background: I'm trying to get the board to output a clean sine. As things are (using the sketch above), I do get an output, but the sine is jittery, jumping around a few Hertz. Changing the MCLK_MULT / MCLK_DIV doesn't make a difference for me. As far as I (my not so good oscilloscope) can tell, the signals look ok (MCKL =~ 24.5MHz, BCLK =~3.07 MHz, Fs = 48KHz)

Thanks for any pointers.
 
Last edited:
I did some further poking around and no dice. Everything seems to be ok (signals, power draw) except the output waveform. I desoldered the isolator to try in Slave Mode, but I'm seeing the same thing.

I haven't got much experience with those codecs (nil, to be exact) ... What are chances I got a dud? Judging from whollender's progress log, they can be a bit delicate (https://hackaday.io/project/5912-teensy-super-audio-board/log/24531-got-last-proto-working) ... Anyways, as a next thing, I guess I'll try to replace the codec.
 
Ok, so I've replaced the codec and things are working now. So far so good. I'm on a Mac and predictably perhaps, I've been running into similar issues as did packetloss69 above, distorted audio over USB. (Output (AudioSynthWaveformSine) and Passthrough is fine)

I've made the corresponding changes to usb_desc.c, usb_dev.c, and usb_desc.h (as above), and it's mostly working now, but not quite. Input is fairly distorted, the output sounds is almost perfect, but it pops every 10 seconds or so; this is how it looks when recorded, simply playing a sine wave from puredata (Macbook #1 > Teensyusbaudio/CS4272 > Audiointerface > Macbook #2).

43352465855_895c9fd924_h.jpg



The #define MACOSX_ADAPTIVE_LIMIT switch doesn't make a difference. With an ipad, it doesn't work at all ("device not supported")


So my new question is: Did anyone manage to get the "Superaudioboard" run as an audio device for MAC/iOS? Since most of the audio library seems to be built around 41.1kHZ, would it make sense to try to use a different crystal / MCLK? Or simply run the codec in Slave Mode, as does the regular Audio Library?

Thanks for any pointers
 
Last edited:
I've been running into similar issues as did packetloss69 above, distorted audio over USB.

Which version of Teensyduino are you using? Click Arduino > About to check.

The mac USB audio problem was fixed quite some time ago. Unless you have a very old version, it really should not be an issue.
 
However, if you are using I2S slave mode (where Teensy receives clocks from the hardware) and you try to combine it together with *any* other inputs or outputs (other than more I2S slave stuff) you can expect many problems.

The audio library is fundamentally designed to run with only a single clock speed.

In I2S slave mode, the external hardware controls the clocks. The USB input & output, and DAC, ADC, PWM all operate using Teensy's clock. Normally you can mix I2S master (and TDM & SPDIF) with all that other stuff, because they all run from Teensy's clock. But if you throw I2S slave mode into the mix, then you're going to have streams running at different clock speeds. Even if they're closely matched, you will get gaps or lost data, because something is running at a different speed than the rest.
 
Which version of Teensyduino are you using?

I'm on 1.8.5., with the current version of the audio library pulled from github.

But yeah, I guess the distortion I'm seeing comes from sticking USB input/output onto the I2S slave mode; it works alright when using Teensy as master (using WM8731, haven't tried with CS4272).

It's odd though that it should work on Windows (or at least that's how I've read the OP). Would it be feasible to properly sync USB to the external MCLK? I only have a vague understanding of what usb_audio.h is doing, in terms of timing. I see it says "update_responsibility = false", so I was half-assuming it'll get pulled along with I2S slave mode.
 
Would it be feasible to properly sync USB to the external MCLK?

The answer depends on what is meant by the word "feasible".

Using the USB audio code that exists today, the answer is no, definitely not feasible. It's all designed around Teensy being the clock master. Perhaps some of that code could be reused, but the tricky parts about isochronous rate feedback are built with the design that the clock comes from Teensy.

If "feasible" means a lot of expert-level USB programming to redesign the USB audio code, then yes, the protocols are capable of doing this sort of thing. But you'd have to rewrite nearly all the isochronous rate feedback stuff to make it happen. Not easy stuff.
 
The answer depends on what is meant by the word "feasible".

Ok, just what I thought. I just went back and removed the I2S isolator again and will run the board with Teensy as master.

Is it possible though that the USB HID is somehow broken in iOS (I've upgraded to 1.43beta since)? - It works fine with my Macbook Pro. I'm getting "The connected device is not supported" whatever I do (Audio, Midi, Audio/Midi ...), which is odd because I've most certainly used Teensy-based Midi devices before. My tablet (iOS 11.4.1) complains even when I plug in a brand-new Teensy ("Teensyduino RawHid not supported").
 
Is it possible though that the USB HID is somehow broken in iOS (I've upgraded to 1.43beta since)? - It works fine with my Macbook Pro. I'm getting "The connected device is not supported" whatever I do (Audio, Midi, Audio/Midi ...), which is odd because I've most certainly used Teensy-based Midi devices before. My tablet (iOS 11.4.1) complains even when I plug in a brand-new Teensy ("Teensyduino RawHid not supported").

ps. so I've googled around a bit, and editing bMaxPower in usb_desc.c doesn't make a difference (I went down to "10"). Technically, it doesn't draw any power whatsoever from the iOS device (ie, I've cut the V_USB trace and feed it 5V via VIN), so unlikely it's a power thing. I suspect something must have changed on the iOS end since even my old projects (which used to work) can't be recognized any longer. Other (non-Teensy) USB devices are recognized no problem.
 
What happens if you change the vendor and product ID numbers?

I'm still getting "Cannot use device" (that is, after changing the two defines in usb_desc.h for USB_AUDIO, that's all it takes, right?; I've also changed the product name for good measure by including <usb_names.h>). Again, this works on my Mac, but not the iPad. It's a bit weird, when trying with the Teensy USB Audio interface and getting the "Cannot use device" error, I have to plug in / plug out my (commercial) audio interface a couple of times until things start working again. It normally starts working 1-2 seconds after plugging it in.
 
How do you connect Teensy to your iPad?

I have an iPad here, but the cable is 8 pin "lightning" to a USB host, not to a USB device as Teensy. Is there a different cable or some sort of adaptor?
 
Not sure, I think it's the same: the official name is "Lightning to USB Camera Adapter".

PS. sorry, was a bit in a rush earlier and realize my answer wasn't particularly precise. What I meant is I'm using the official/Apple "Lightning to USB Camera Adapter", which works with USB devices, at least some (like audio/midi interfaces, or that's what I've been using). It also used to work with Teensy, literally the same thing/code/iPad until maybe a few weeks or months ago. (This thread looks like the same/similar issue). So I suspect it must be some iOS thing, though I wouldn't know what as everything else seems to be working much like before, even those cheapo Chinese USB/midi dongles; as mentioned, I'm powering the Teensy (3.2) from a separate supply, so it's unlikely a power draw issue.
 
Status
Not open for further replies.
Back
Top