Jump to content
  • 0

Correct Input and Outputs for PMODI2S?


Terence D

Question

Hi - I've recently purchased a PMODI2S which I'm trying to use with my Tiva LaunchPad TM4C123G.  The TM4C123G doesn't doesn't have I2S, but TI has a good document of how it can be emulated using dual SPI's.  I've setup the PMODI2S inputs as follows:

Pin 1 (MCLK) - Sending a 6.25 MHz 50% duty cycle signal from the TM4C123G to the PMODI2S

Pin 2 (LRCLK) - Sending a 24.4141 KHz 50% duty cycle signal from the TM4C123G to the PMODI2S (This is 1/256th of 6.25 MHz)

Pin 3 (SCK) - I have hooked up to my logic analyzer and see no signal output

Pin4 (SDIN) - I do not yet have this hooked up to anything

Pin 5 (GND) - Hooked up to the GND pin of my TM4C123G

Pin 6 (VCC) - Hooked up to the +3.3V of my TM4C123G

After reading the PMODI2S reference manual it's my understanding I should be seeing an output signal from the PMODI2S on the SCK pin.  Can anyone confirm my understanding is correct?  Thanks.

Link to comment
Share on other sites

19 answers to this question

Recommended Posts

The STM32F429 has the choice of configuring the I2S communication using the PLL or SAI.  It seems like the PLL is the more frequent choice so I'm using it.

Using my logic analyzer to view the MCLK and LRCK lines I see that the MCLK to LRCK ratio is very close to being right (256:1).  I've attached a screenshot of this below.  The MCLK cycle is roughly 80 nanoseconds and the LRCK cycle is roughly 20 microseconds.  My logic analyzer's peak sample rate is 50 MHz so I'm limited in getting measurements with higher precision than this. 

My I2S sample rate is set to 48,000 Hz which should mean a sample roughly every 20 microseconds (i.e. what the LRCK is roughly showing).  The odd thing I'm seeing are random logic changes in the LRCK as shown in the screenshot below.  These don't happen every sample but happen maybe ten or twenty times per second and result in glitch sounds in the audio output.

As mentioned I'm thinking my problems rest with my clock configurations.  The clock configuration in the STM32F4 is not trivial.  I have a separate thread in the STM forum where I've been trying to fully understand this.  If interested, this thread is here.

LogicAnalyzer.png

Link to comment
Share on other sites

Okay, so I've got fully working code for the STM32F411 which has a CS43L22 DAC on the board.  Note that this is not the same as the CS4344 that is on the PmodI2S.  The CS43L22 has a whole set of initialization steps that the CS4344 does not and also does communication with I2C and I2S.  I still want to get the PmodI2S working with my STM32F429.  My next steps are going to likely include:

  1. Comparing my STM32411/CS43L22 code with my STM32F429/CS4344 code and making tweaks to the latter.
  2. Getting DMA to work first with the STM32411/CS43L22 and then hopefully leveraging this information to get DMA to work with the STM32F429/CS4344.

If anyone is interested in my ongoing trials and tribulations with the above please let me know.

Link to comment
Share on other sites

Good insights, thanks, Stephen.  Some thoughts on each one of your points (with respect to your original numbering):

1) Based on this blog entry it sounds like you can use lower sample rates.  Specifically the quote: "Note that you are not required to use the maximum bit rates for this chip.  You can send in lower bit rates as long as the LRCLK to MCLK ratio is within the following ratios as required by the CS4344".  Additionally, on page 2 of the Digilent PmodI2S documentation it says "A table of commonly used sample rates and their corresponding MCLK rates from the CS4344 datasheet is provided below".  I was hoping this meant that I could use different sample rates.  I use 8KHz because that is the only sample rate shown in the STM32F4 datasheet table which requires a master clock yet has no error:

image.png.9e80080b21aba8550fe71fcbcb570750.png

 

3) Good suggestion!  I tried this, and the funny thing is that this is that the audio tone just increases.  Which makes sense in a way that it's less instructions per sample - i.e. instead calling the same chunk of code for each sample it should only have to call it for x samples (x being the third argument to HAL_I2S_Transmit - I tried various values).  However, I would suspect the SPI data register would "block" at a periodic rate specific to my 8 KHz sample rate, which is why I find the pitch shifting much higher odd.

4) Another good suggestion!  As an experienced software engineer I should know much better than to not check the return code.  For some reason I didn't realize the HAL_I2S_Transmit was returning a result.  So, I'm doing very similar to what you suggested: I'm simply toggling a GPIO pin when a none HAL_OK return code is obtained.  And it was definitely getting toggled frequently when viewing with my logic analyzer.  With farther tweaking I see it's frequently returning a HAL_TIMEOUT error code.  Changing the timeout parameter passed to HAL_I2S_Transmit to a larger value causes this error to go away but then audio output is either non-existant or even farther distorted.

Based on what I've found in item 3 above I'm thinking there is something fundamental I'm missing with how I2S works on the STM32 board.  I've (just now) managed to get a hold of a similar STM32 board (an STM32F411) that actually has an very similar DAC on the board itself and have an audio example from STM working on this board.  I'm going to dig through the code and fully understand how that works in hopes of it shedding some light on how to get the STM32F429 to work with the Digilent PmodI2S.

I've made myself a reminder (a week out) to return to this thread and post my results.

Stephen - Thanks for all your help with this so far.  You've been very helpful and I very much appreciate it.

-Terence

Link to comment
Share on other sites

Hi Terence,

1) Not sure how important this is but CS4344 datasheet lists 32kHz as its lowest sample rate, you're running at 8kHz.

2) Source code for HAL_I2S_Transmit

3) You could try this:

double up sample array:

uint16_t sawtoothUnsigned16bit[96] = {
0x0, 0x0, 0x555, 0x555, etc...
};

Then:

HAL_I2S_Transmit(&hi2s2, &SINE_TABLE[0], 96, 0);

4) You're not checking the return value from HAL_I2S_Transmit. Setup an 8 bit GPIO for output and write the low byte to the GPIO. Use your lab monitor to see if you get any non-zero values.

Link to comment
Share on other sites

Thanks Stephen - Great reply!  Really appreciate your interest in helping me with this.  I actually have a "sister thread" going on at the STM32 MCU forum here.  A forum user over there replied overnight similar to your suggestion - that there might be something going on in how timely I'm sending the data to the SPI register.  I've just replied to that post including details.  Basically I'm using the STM32 hardware abstraction layer API to send the sine wave data to the SPI (I2S) data register.  This is occurring in the main while loop of the program (the while loop that occurs after setup is complete).  There is no other processing or any interrupts, but essentially, this is a "polling" operation.  Here's the code if interested:

  while (1)
  {

      if (HAL_I2S_GetState(&hi2s2) == HAL_I2S_STATE_READY)
      {
          HAL_I2S_Transmit(&hi2s2, &SINE_TABLE[index], 1, 0);

          if(!channel) channel = 1;
          else channel = 0;

          if (channel)
          {
              index++;
              index = index % 256;
          }
      }
  }
 

And, as I mention on the "sister thread":

Possibly I need to offload the data transfer duty to DMA?  I have not yet done DMA with this development board (STM32F4) I have done it with a different ARM Cortex-M4 board though (the Texas Instruments TM4C123G).  I cannot use the TM4C123G for this though as it does not have I2S support. 

I think my next plans of action are as follows (in order):

  1. Not use the HAL to transfer the audio data but write directly to the SPI data register inside the while loop and see if the issue is resolved.
  2. Attempt to use DMA to transfer the audio data instead of the infinite while loop.

Let me give at least action #1 a try and report back.  Achieving action #1 should take minimal time.  Action #2 is likely going to take substantially longer, however, I did plan to work my way up to using DMA for audio transmission with this board anyway, so I suppose there is no time like the present to get started :)

Thanks again,

Terence

PS: Using FPGA's to do audio processing sounds AWESOME.  Hope to work my way up to this before long.

Link to comment
Share on other sites

Hi Terence,

great to see you're making progress.

I suspect the glitch is due to a hiccup in the data delivery software. For some reason the wrong value is making its way into the I2S channel. This could be due to 1) corrupted buffers/FIFOs, 2) timing delays, 3) debug or 4) interrupt priority inversion.

I2S is an example of a 'hard' real time system. A new 32/48 bit value needs to be ready every 1/Fs th of a second, no ifs or buts. The I2S hardware will generally provide a FIFO bank (say 16 words), giving you a certain amount of buffer time. Your code needs to keep the buffer from becoming empty. I would normally use a DMA channel to service the I2S FIFO low signal (interrupt). This needs to be the highest priority task in the system. Polling probably won't cut it.

I seem to remember you saying you were using an ST provided function. You will need to look at the source code to try and work out how it works. Is it using interrupts and/or DMA? Are there other interrupts in the system? The TI Cortex M4's have customisable interrupt priorities, ST are probably the same. Are there higher priority interrupts getting in the way? Do you have a single mainline testing/waiting for input and trying to deliver data?

There are LOTS of things that it could be. This sort of thing can be difficult to debug as you generally need to run the processor at full speed without any breakpoints. It helps to flip GPIO bits around with the logic probe attached to see what is going on. For example, set GPIO1 on entry to an interrupt handler and clear it on the way out. Use a different GPIO for each distinct section of code and see what it gets you. If your lab device allows you to capture analog and digital signals together see if you can find any correlation between the glitch and the code path.

For comparison, I am driving my PMODI2S with an Arty FPGA board. MCLK = 12.288MHz and LRCK is 64kHz (24bits/channel, internal SCK @MCLK/4). The internal calculation engine runs at 12,288,00MHz, same as MCLK. I don't buffer anything, my engine is hardcoded to load a 48 bit shift register every 1/64,000th of a sec. FPGA's make some things MUCH easier ;)

Cheers,
Stephen

 

 

Link to comment
Share on other sites

Stephen - Apologies for the late reply.  I spent a good bit more time understanding the clock configurations on my MCU and I now have better I2S clock signals going from the my STM32F429 MCU to the Digilent Pmod2S DAC as shown below.  No random signals showing up that I had before:

image.thumb.png.66079aeb63e4dc9c65e2284132651307.png

 

I've configured the I2S to be just a sample rate of 8 KHz and am sending the same 256 sample cycle of a sine wave from the MCU to the Pmod2S.  The sine wave sounds good EXCEPT for random "clicks" - maybe 5 to 10 per second.  Here is an example of such a "click" I've obtained using my oscilloscope:

image.thumb.png.21ca18a8faddaf8f3c121f04e53443ed.png

 

Similarly, I've recorded the audio coming out of my speakers with a mic.  Here is an example of the "click" when viewed in Audacity (audio editor software):

image.png.e7b5076612f82a428a413dbc0fc99223.png

 

As far as I can tell I have everything configured correctly, so I'm not sure what the issue is.  Any thoughts on your end would be very welcomed.

Thanks,

Terence  

Link to comment
Share on other sites

Hi Terence,

the waveform doesn't look great but it sort of looks like a 1kHz sawtooth with a fair bit of capacitance. I suggest using the analog ports on you lab tool. Connect the probe grounds to the shield (sleeve). Connect the two probe tips to the left and right channels (tip & ring).

Declaring the array signed/unsigned makes no difference because you're 1) specifying the values in hex and 2) not performing any computations with them. The CS4344 cares, because it expects the values to be signed. You need to understand that sending 0x8000 (-32768) will send the output to its most negative point. Sending 0x7fff (+32767) will send the output to its most positive value. A zero value will result in a value halfway between the two extremes.

The digital output needs to be MSB first, that means the sign bit (bit 15). Note that for the CS4344 (fig 7 again) the MSB needs to be in the second bit position following the LRCK transition. The first bit position should be occupied by the LSB from the previous frame. The little peak at the bottom of your sample suggests the framing is not quite right.

Regards,

Stephen

Stereo_Pin_Plug.jpg

Link to comment
Share on other sites

Hi Stephen - Thanks again for your thoughts.  Having someone question my setup (other than myself) is very helpful.  Specific answers to your questions:

12 hours ago, Stephen D said:

 Have you been able to find an I2S example program for the STM?

I've scoured the web with my best Google-Fu and the best I've been able to find is the example I've been using so far from here.  ...Since finding this, I've actually learned about the STM32CubeMX application.  It's a software application tool for STM32 boards that allows you to visually configure peripherals and clock speeds and the will generate code with the given configuration.  I've used this to configure the clock and setup the I2S and now no longer have random glitches on the LRCK.  However, my output signal is very distorted.

As an example of how distorted, see the audio waveform screenshot below.  To make analysis simpler, I've switched from outputting a sine to a sawtooth.  The sawtooth is at 1,000Hz.  The sample rate is 48,000 Hz.  So I simply have 48 samples that go from the lowest 16 bit value to the highest.

13 hours ago, Stephen D said:

Do you have an oscilloscope? What does the analog output look like?

I have an Embedded Artists LabTool.  I've only used it as a logic analyzer, but it does have two oscilloscope inputs.  Sorry, stupid question: How exactly do you analyze an audio output signal with an oscilloscope?  The PmodI2S has a typical 1/8" stereo output jack.  I know that I can only monitor one of the stereo channels (left or right) with the oscilloscope.  I have a 1/8" stereo wire plugged into the PmodI2S.  This wire has a male adapter on one end and spliced wires on the other.  Looking at the stereo cable, each channel has two separate wires associated with it - I suspect a positive and a negative.  Not sure which should be hooked up to the LabTool's oscilloscope single wire input...  Any suggestions would be appreciated.

 

14 hours ago, Stephen D said:

It is worth checking the relationships between: (CS4344 Fig 7)

1) LRCK and SCLK. LRCK should change on SCLK falling edge.

2) SCLK and SDATA. SDATA should change on SCLK falling edge (SDATA gets sampled on rising edge of SCLK).

Attached is the latest logic analysis of all four lines from the new program generated using the STM32CubeMX.  I just took this now for the first time and clearly the MCLK doesn't look right...  I would think the duty cycle should always be 50%...  I will look into this right after this post.

 

14 hours ago, Stephen D said:

You mention the data being unsigned (uint16_t). This is incorrect, it should be signed (int16_t). -ve sine wave peak occurs at 0x8000, +ve at 0x7fff. I generally use a spreadsheet to calculate this stuff then output as .csv before importing into code.

 

Hmmmm...  The transmit function of the STM32 HAL API takes uint16_t as it's data.  I first generate this data with an audio editor.  Then I use a simple C program to display the data as a c array.  Below are examples of my sawtooth cycle as both an unsigned int array and signed int.  When using either of these the output from the speakers sounds and appears identical - same as that shown in the screenshot of the waveform below.

uint16_t sawtoothUnsigned16bit[48] = {
0x0, 0x555, 0xaab, 0x1000, 0x1555, 0x1aab, 0x2000, 0x2555,
0x2aab, 0x3000, 0x3555, 0x3aab, 0x4000, 0x4555, 0x4aab, 0x5000,
0x5555, 0x5aab, 0x6000, 0x6555, 0x6aab, 0x7000, 0x7555, 0x7aab,
0x8000, 0x8555, 0x8aab, 0x9000, 0x9555, 0x9aab, 0xa000, 0xa555,
0xaaab, 0xb000, 0xb555, 0xbaab, 0xc000, 0xc555, 0xcaab, 0xd000,
0xd555, 0xdaab, 0xe000, 0xe555, 0xeaab, 0xf000, 0xf555, 0xfaab,
};

int16_t sawtoothSigned16bit[48] = {
0x8001, 0x8556, 0x8aab, 0x9000, 0x9555, 0x9aaa, 0x9fff, 0xa554,
0xaaa9, 0xaffe, 0xb553, 0xbaa8, 0xbffd, 0xc552, 0xcaa7, 0xcffc,
0xd551, 0xdaa6, 0xdffb, 0xe550, 0xeaa5, 0xeffa, 0xf54f, 0xfaa4,
0xfff9, 0x54e, 0xaa3, 0xff8, 0x154d, 0x1aa2, 0x1ff7, 0x254c,
0x2aa1, 0x2ff6, 0x354b, 0x3aa0, 0x3ff5, 0x454a, 0x4a9f, 0x4ff4,
0x5549, 0x5a9e, 0x5ff3, 0x6548, 0x6a9d, 0x6ff2, 0x7547, 0x7a9c,
};

 

RecordedSawtooth.png

LatestLogicAnalysis.png

Link to comment
Share on other sites

Hi Terence,

can't help with STM configuration.

Glitches on LRCK are probably bad. Have you been able to find an I2S example program for the STM? Look for application notes against your processor and other related processors

Do you have an oscilloscope? What does the analog output look like?

It is worth checking the relationships between: (CS4344 Fig 7)

1) LRCK and SCLK. LRCK should change on SCLK falling edge.

2) SCLK and SDATA. SDATA should change on SCLK falling edge (SDATA gets sampled on rising edge of SCLK).

You mention the data being unsigned (uint16_t). This is incorrect, it should be signed (int16_t). -ve sine wave peak occurs at 0x8000, +ve at 0x7fff. I generally use a spreadsheet to calculate this stuff then output as .csv before importing into code.

Link to comment
Share on other sites

Hi Steve - Thanks for the reply.  Currently I'm simply trying to send a sine wave from my STM32F429 Discovery board to the PModI2S DAC.  In the program that runs on the STM32F429 I have a simple array of 256 uint16_t values that make up a single cycle of a sine wave.  I continually loop through this array sending the values to the PModI2S.

At a sample rate of 48000 Hz, the audio output from the PModI2S to the speakers hooked up to it should be a 187.5 Hz sine wave.  When I do get audio (as I tweak various clock and I2S settings in the program running on the STM32F429) I'm getting audio that is far off from that that 187.5 Hz tone I expect I should be getting.  This is why I'm quite certain it's related to my clock settings in the program.

Any suggestions on your end would be welcome.  Thanks for your continued interest in helping me get this figured out.

-Terence

Link to comment
Share on other sites

Hi Terence,

good to hear you've got it going. Have played around with the TI Tiva chips, another Cortex-M4 design. Understand what you're saying about clock settings.

Replacing the main clock crystal with something a little more audio friendly is worth considering if you want to use one of the "standard" sample rates.

What exactly are you trying to do?

Regards,

Stephen

Link to comment
Share on other sites

18 hours ago, Stephen D said:

I'm using it with an Arty A7 to generate 91 sine waves in an attempt to clone a Hammond tone wheel organ.

That's AWESOME!!!  I'd love to get into audio processing w/ FPGA's but have my hands full with Cortex-M boards right now.

So, good news: I got the PModI2S outputting audio.  The audio is that of a single sine wave cycle that loops infinitely. 

Bad news: I don't have the clock settings quite right still and the pitch of my sine wave coming out of the speakers hooked up to the PModI2S is not quite right.  I'm fairly certain the issue is properly configuring the clock settings on the STM32F... Which is not trivial.

I'm confident I'll get it figured out though with some more work which I should be getting to shortly.  If anyone is interested in my code to make this work please let me know and I'll come back and post a link here once I have it working 100% correctly.

   

 

Link to comment
Share on other sites

Hi Terence,

I'm afraid the PModI2S is the limit of my I2S experience. I'm using it with an Arty A7 to generate 91 sine waves in an attempt to clone a Hammond tone wheel organ.

The master side of the interface is custom RTL (verilog). Basically a numerically controlled oscillator followed by a ROM (sine wave table) followed by a shift register.

I had a quick look at the STM32F429 reference manual. On page 904:

  1. I2S Philips standard

    For this standard, the WS signal is used to indicate which channel is being transmitted. It is activated one CK clock cycle before the first bit (MSB) is available.

Sounds like the CS4344 is 'Philips Standard' and will work with the STM processor.

Cheers,

Stephen

 

Link to comment
Share on other sites

Hi Stephen - Thanks for the information.  I just looked at figure 7 of the CS4344 datasheet and see what you're saying.  Unfortunately, I never got the PModI2S working with my TM4C123G board.  I instead switched to another DAC at the time. 

HOWEVER, funny timing, I've been playing around with a new board - an STM32F429 Discorvery board that actually has I2S support (unlike the TM4C123G) and I've just in the last few days started working with the PmodI2S again trying to get it to work with the STM32F429.

Please correct me if I'm wrong, but I imagine the 1 bit delay between the edge of the LRCK and the MSB of the SDATA is standard for I2S communication, right?

Thanks in advance,

Terence 

Link to comment
Share on other sites

Hi Terence,

you've probably worked it out by now but I'll add this anyway.

A 'gotcha' with the CS4344 can be found in Figure 7 of the data sheet. There is a 1 bit delay between the edge of LRCK and the MSB beginning on SDATA.

In other words, the LSB of the previous L/R channel value is found as the first bit of the following R/L channel frame.

Regards,

Stephen

Link to comment
Share on other sites

@D@n - Thanks so much for your reply.  Yeah, I definitely should've looked closer at the CS4344 datasheet.  For whatever reason I got overly focused on the Digilent documentation.  Thank you for pointing out that the SCLK is an input.

As for the sample rate, my problem is that with the Tiva LaunchPad TM4C123G I believe the fastest clock I can send out a pin is 25 MHz and then fractions of that.  For example, the next fastest being 16.667 MHz, then 12.5 MHz, then 10 MHz and so forth.  I happened to come across this blog post where the author used a non-standard sample rate with the PMODI2S.  My understanding is the MCLK just has to be a 256x, 384x, etc multiplier of the LRCLK and it could work with any sample rate (I'm of course open to the idea that I may be incorrect with regards to this functionality).

I have a pretty good understanding of DSP fundamentals and a lot of experience with digital audio.  I would prefer to have an audio output sample rate of 44.1KHz but I'd first just like to get the chip to work at any reasonable sample rate (my definition of "reasonable" being maybe 20KHz or higher) and then go from there to see if I can improve the sample rate.

I'm going to carefully study the CS4344 datasheet and see what additional insights I might be able to glean.  I'll gladly post back when I've made more progress.  Again, much appreciate your reply. 

-Terence 

Link to comment
Share on other sites

@Terence D,

If you look at the data sheet for the CS4344, and specifically on page four of that datasheet, you'll find that the DEM/SCLK pin is an input signal to the chip, not an output.  Digging a bit further, page 12 discusses how the SCLK can be generated internally, but also states that when doing so the DEM/SCLK pin is used as an emphases/de-emphasis selection pin.  So ... I think what's going on is that while the device will generate an SCLK signal, I don't think that signal ever leaves the chip.

Looking over your other numbers, a 24.4kHz LRCLK suggests a 24.4kHz sample rate.  That's a not an audio rate I'm familiar with, neither is it one of the rates listed on 12 of the spec as being a supported rate.  Are you sure you need this rate?  If your incoming data is at this rate, you might wish to upsample the data to a higher rate.  I put a resampling tutorial together some time ago although ... it does assume a certain level of DSP understanding.  Holler if you need help, and I can help you go over it if this is something you decide you need to do.

Hope that helps,

Dan

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...