cancel
Showing results for 
Search instead for 
Did you mean: 

Periodically interrupt driven SPI

Omar Suárez
Senior
Posted on January 29, 2018 at 14:48

Hello,

I am trying to set up a project using an STM32F746ZG and an external DAC communicated by the SPI3. The idea is to transmit data from the MCU to the DAC periodically (using a timer and its interrupt) and use the callback function for SPI transfer complete to check whether the data transmission has ended. I need to send 16 bits data with MSB first.

To send the data I use a buffer which I need to acces each of the elements load in an array and transmit every uint16_t value over the SPI. I need to transmit one 16-bit value at a time (controlled by the timer).

Here is some code snippet so you can take a look,

 const uint16_t aTxBuffer[32] = {2047, 1648, 1264, 910, 600,  345,   

                    156, 39,  0,  39,  156,  345,  

                    600, 910, 1264, 1648, 2048, 2447,  

                    2831, 3185, 3495, 3750, 3939, 4056,  

                    4095, 4056, 3939, 3750, 3495, 3185,  

                    2831, 2447};

uint8_t cont = 0;

...

...

int main(){

...

...

...

 while (1)

  {

       /* is it time to send data? */

        if(flagStartSPI_DAC){

            if(HAL_SPI_Transmit_IT(&hspi3, (uint8_t*)aTxBuffer[cont], 1) != HAL_OK){

                    _Error_Handler(__FILE__, __LINE__);

                }

            

            flagStartSPI_DAC = 0;

        }

        /* has the data been transmited over SPI yet? then start timer again */

        if(flagStart_TIM){

            flagStart_TIM = 0;

            HAL_TIM_Base_Start_IT(&htim6);

        }

  }

}

...

...

...

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi){

    cont++;

     

   /* is it the last values in the array? */       

    if(cont==32){

        cont = 0;

    }

   /* led on for debugging pourposes */

    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);

   /* start timer */

    flagStart_TIM = 1;                

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){

    

   /* time to send data over the SPI? */

    if(htim->Instance == TIM6){

        /* set the flag */

        flagStartSPI_DAC = 1;

    }

}

The problem I am experimenting now is that the SPI values I read using an logic analyzer are not correct and the SPI interrupt takes place only the first 8 timer triggers.

Anyone can help with this?

Thanks in advanced,

Omar

#stm32f-spi #interrupts #stm32f7
7 REPLIES 7
Andrew Neil
Evangelist III
Posted on January 29, 2018 at 16:12

the SPI values I read using an logic analyzer are not correct

How, exactly, are they 'not correct' ?

SPI interrupt takes place only the first 8 timer triggers

Is that because the timer stops?

Or the SPI stops transmitting?

Or what?

Uwe Bonnes
Principal III
Posted on January 29, 2018 at 16:42

In a similar situation, I have set up the timer to trigger a DMA transfer from the array to the SPI Register. No interrupt needed for each transfer.

Posted on January 29, 2018 at 16:56

Hi Andrew,

the MOSI, CLK and NSS signals seems to be working syncrhronized but the values written in the MOSI have different value than the array values.

The timer continues to trigger the timer interrupt callback, but the SPI doesn't seem to work anymore transmitting data.

Posted on January 29, 2018 at 17:01

Hi Uwe,

can you copy your config code to see how did you do the setting up to work with the DMA? One thing I did mention is that in the real application I would need the use of a double buffer so I can write one with new values while the other one is being read so the system can switch between them and also can refresh with new values (I need to generate a specific non-periodic waveform over time).

Posted on January 31, 2018 at 13:43

The program used Nut/Os trunk

https://sourceforge.net/p/ethernut/code/HEAD/tree/trunk/

  and has comments in german.  If you think the code is of help for you. let me know and send my your email address
John Craven
Senior
Posted on January 31, 2018 at 14:48

One thing you need to do is move the timer start call out of the loop.

You only need to start the timer once, before the loop.

henry.dick
Senior II
Posted on January 31, 2018 at 15:01

The flow makes no sense to me. I don't know why you need to start and restart the timer.

If the spi routine is quick, I would simply set up the timer to interrupt periodically and in the is, clear the flag and send the data.

If the spi routine takes lots of time to execute, use the timer to set a flag. Check the flag in the main loop. If the flag is set, send the spi data and then reset the flag.

Shouldn't be materially more complex than that.