I was trying out a sound experiment, starting off with sample code which sent data to the Discovery F4's audio codec using I2S. The sample code used polling in the main loop and sent data when the transmit buffer was empty.

I set up an interupt handler for SPI (in I2S mode) to do the same thing. I set a flag when the interupt was generated and then this flag triggered transmission of data in the main loop. The problem is, the interupts were generated too quickly and the code in the main loop never executed. I had to disable and enable interupts for this to work.

void SPI3_IRQHandler ( void )
    STM_EVAL_LEDToggle(LED3); // NC
    if (SPI_I2S_GetITStatus(SPI3, SPI_I2S_IT_TXE) != RESET) {
        SPI_I2S_ClearITPendingBit(SPI3, SPI_I2S_IT_TXE);

        if (SPI_I2S_GetFlagStatus(CODEC_I2S, SPI_I2S_FLAG_TXE)) {
            transferFlag = true;
            ready = false;

Main loop:

        if (transferFlag){
                //generate the sound
        SPI_I2S_SendData(CODEC_I2S, value);
            transferFlag = false;

I even made the generating sound very simple (like value = 1000), and it still did not work, without enabling and disabling the interupts. In fact, LED5 and LED6 never turned on at all, indicating that the main loop was not entered. Additionally, I placed the "generating sound and transmitting to SPI" code in the interupt handler. This worked, but the sound was softer the current code shown above.

The Cortex M4 on the STM is definitely not that slow, the FPU is also turned on. I plan on making a DMA version of this, but I do not think turning interupts on and off is a good solution.

  • \$\begingroup\$ Is transferFlag declared volatile? \$\endgroup\$ – Turbo J Jun 30 '13 at 12:50
  • \$\begingroup\$ @TurboJ Yes it is. Either way, since transferFlag is initially set to True, the main loop should have executed at least once, which would make the LED's turn on \$\endgroup\$ – user929404 Jun 30 '13 at 15:35

the interupts were generated too quickly and the code in the main loop never executed

This is always the case when you forgot to clear an interrupt flag - the Handler gets executed again and again.

The code above does not clear the SPI_I2S_FLAG_TXE flag in the CODEC_I2S register. There may be other flags you need to clear - look in the datasheet/manual.

| improve this answer | |
  • \$\begingroup\$ Thanks, I will look into this. I cleared the SPI_I2S_IT_TXE flag, but I will look up the others later today. \$\endgroup\$ – user929404 Jul 1 '13 at 6:27

You cleared the SPI_I2S_IT_TXE flag, but this flag only means "Transmit Buffer Empty", and since you didn't write anything in the transmit buffer in your interrupt, the flag is immediatly set again by the hardware after you clear it.

That is why the line SPI_I2S_SendData(CODEC_I2S, value); must be in your interrupt, not in your main loop. As a side effect, writing data to the transmit buffer clears the TXE flag, therefore you don't have to clear it manually.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.