TLDR: All of the code for the SAB using either the Teensy or FPGA as a controller had mistakenly set the sample rate to 32kHz instead of 48kHz due to an inaccuracy in the datasheet. The code in github has been fixed so that the sample rate is correct.
I was recently trying to help someone who had built a board up, but couldn't seem to get the correct frequency output. They were trying to simply output a 1kHz sine wave using the Teensy Audio library. Everything seemed to be working, but the output was at 667Hz instead of 1kHz. The sample rate seemed to be at 32kHz instead of 48kHz for some reason.
The CS4272 codec has a number of different modes, I designed the board to use a 24.576MHz crystal, and only operate in master mode, where the codec generates all the clocks used for the I2S interface, including the sample rate (corresponding with the frame clock or L/R clock). The odd thing is, the datasheet only specifies 2 possible divide ratios for the sample rate in this configuration, 256 and 512, and 512 results in a valid sample rate in the 'single speed mode':
I chose a divide ratio of 512 for a sample rate of 48kHz (256 would result in a sample rate of 96kHz, which isn't valid for the single speed mode, so only works with lower crystal frequencies). The Ratio1 bit is clearly defined for this case, but the Ratio0 bit is a 'don't care' so I wrote the code to write '11' to this field, just in case there happened to be an issue with bit ordering.
The codec has a second mode, where there is no external crystal, and it is configured to receive MCLK, the master clock in the I2S interface, instead of generating it from the crystal. In this configuration, the Ratio bits are slightly different:
Notice in this table, that setting the Ratio bits to '11' results in a divide ratio of 768, which results in a sample rate of 32kHz if the master clock is 24.768MHz.
This seemed to point to a startup issue causing the codec to start in the wrong mode. This is really curious because the MCLK pin on the codec is supposed to be an input in this configuration, but then there wouldn't be anything driving the pin at all. I thought that maybe this problem was a one off board problem, and that some interference between the clock oscillator and MCLK pin was causing a startup issue.
After much troubleshooting, however, it turns out that all the boards have this problem, even the ones that I've done all the performance testing on. Oops!
I hadn't ever seen the problem before because I had only been performing loopback testing, so all the results looked fine. I had played a sine wave out of a speaker, but hadn't noticed that the output was at way too low of a frequency.
I had played music through it using the Raspberry Pi, but the part of the kernel driver that sets the divide ratio already existed (written for the CS4271, which has a compatible register set), so it actually worked at the correct sample rate.
I never thought to go back and double check the sample rate because I don't have good enough equipment to measure the performance I was trying to achieve, and, more importantly, the datasheet indicated that any other sample rates were effectively impossible in the configuration used.
I triple checked the startup sequence used, but it also matches the datasheet to a T. It just looks like the codec's behavior doesn't match the datasheet in this configuration.
Luckily, it is an easy fix to get the correct sample rate. The correction is just to follow the second table, and set the divide ratio bits to '10' instead of '11'. Needless to say, all of the code in github has been updated to set the correct sample rate.
Unfortunately, this means that all the performance data that I had collected was at a sample rate of 32kHz instead of 48kHz, and the tones used were at 667Hz instead of 1kHz. I had run a THD+N test using the Raspberry Pi which would have used the correct sample rate, and the results were good, so I didn't think there would be a major difference from the original data, but I wanted to be sure.
I re-ran the THD+N test using the Teensy at the correct sample rate, and a real 1kHz tone, and got performance that was just as good as before. Here's a shot of the results (output at -1dBFS), with -99.5dB THD+N:
So, anyway, as a parting note, don't always believe the datasheet, even for things that seem like they shouldn't be a problem. And verifying the correct operation on a separate piece of equipment is always a good idea!