cancel
Showing results for 
Search instead for 
Did you mean: 

SPI_Transmit_AND_Receive_Interrupt_FLAG_At_Same_Time

M N
Associate II
Posted on January 27, 2017 at 23:28

Hi.

I have problem by SPI that is :

When i want to send data for example in slave mode during receiving from master. data will corrupt ( if i just receive data and send to UART it works fine). I think it happens Because both TXE and RXNE occurs at same time and when MCU is in ISR data will rewrite in data register before transfer to Tx/Rx buffer  . How can i Handle this in continuous transmission ?  . it's my code :

-------------------------------------------------------------------------↓

//Slave Part

void

SPI2_IRQHandler(

void

){ 

static char counter =

0x40

;

           

 if

( SPI2->SR & SPI_SR_RXNE ) {   

                sendToUart(SPI2->DR);

            }

          

 if

( SPI2->SR & SPI_SR_TXE ) {               

                SPI2->DR = counter;

                counter++;

                if(counter >=

0x5B

)counter=

0x40

;          

            }          

 }   

-------------------------------------------------------------------------↑

1 ACCEPTED SOLUTION

Accepted Solutions
Posted on January 29, 2017 at 23:16

Huh.

Try to:

- initializemaster SPI first - otherwise the lines are floating while the slave is already initialized thus might pick up spurious clocks

- decrease speed setting in OSPEEDR - the 25MHz should be enough

- set realterm to display hex and post what's those 'incorrectly received' bytes

I admit I have no explanation why changing data transmitted by slave should matter.

Style advices:

Don't use magic constants, it's a considerable effort to decipher them. Instead, use the device header defined constants throughout. You might want to define the non-single-bit bitfield values ST don't define. E.g. I use

#define  DMA_SIZE__BYTE            0

#define  DMA_SIZE__HALFWORD        1

#define  DMA_SIZE__WORD            2

#define  DMA_PRIORITY__LOW         0

#define  DMA_PRIORITY__MEDIUM      1

#define  DMA_PRIORITY__HIGH        2

#define  DMA_PRIORITY__VERY_HIGH   3

#define  DMA_DIR__P2M              0

#define  DMA_DIR__M2P              1

[...]

      DMA1_Channel3->CMAR  = (uint32_t)redLedTable;

      DMA1_Channel3->CPAR  = (uint32_t)&LPTIM1->CMP;

      DMA1_Channel3->CNDTR = sizeof(redLedTable) / sizeof(redLedTable[0]);

      DMA1_Channel3->CCR   = 0

        | ( 1 *                  DMA_CCR_EN      )    // Channel enable

        | ( 0 *                  DMA_CCR_TCIE    )    // Transfer complete interrupt enable

        | ( 0 *                  DMA_CCR_HTIE    )    // Half Transfer interrupt enable

        | ( 0 *                  DMA_CCR_TEIE    )    // Transfer error interrupt enable

        | ( DMA_DIR__M2P *       DMA_CCR_DIR     )    // Data transfer direction

        | ( 1 *                  DMA_CCR_CIRC    )    // Circular mode

        | ( 0 *                  DMA_CCR_PINC    )    // Peripheral increment mode

        | ( 1 *                  DMA_CCR_MINC    )    // Memory increment mode

        | ( DMA_SIZE__HALFWORD * DMA_CCR_PSIZE_0 )    // PSIZE[1:0] bits (Peripheral size)

        | ( DMA_SIZE__HALFWORD * DMA_CCR_MSIZE_0 )    // MSIZE[1:0] bits (Memory size)

        | ( DMA_PRIORITY__LOW *  DMA_CCR_PL_0    )    // PL[1:0] bits(Channel Priority level)

        | ( 0 *                  DMA_CCR_MEM2MEM )    // Memory to memory mode

      ;

You get the point.

Don't do anything which would hold up ISR, here, USART transmission.

JW

View solution in original post

12 REPLIES 12
M N
Associate II
Posted on January 28, 2017 at 10:37

For more detail .I'll write two program here one of them works good but the next one data will corrupt . i'll attach the result picture;

---------------------------------1-Ok----------------------?

void

SPI2_IRQHandler(

void

){       

            if( SPI2->SR & SPI_SR_TXE ){

                SPI2->DR =

0xFF

;    

            }  

            if( SPI2->SR & SPI_SR_RXNE ){

                stringBuffer[counterInMaster] = SPI2->DR;

                counterInMaster++;

                if(counterInMaster >

25

){

                    counterInMaster =

0

;                

                    stringBuffer[

26

] = '

\0

';

                    send2Usart2(stringBuffer);                

                    }        

            }

    }   0690X00000603a6QAA.jpg

-----------------------------------------------------------------?

------------------------------2-corrupt----------------------?

void

SPI2_IRQHandler(

void

){

            if( SPI2->SR & SPI_SR_TXE ){

                SPI2->DR =

0x41

; // ?

any character lead to corrupting data

 

            }

            if( SPI2->SR & SPI_SR_RXNE ){

                stringBuffer[counterInMaster] = SPI2->DR;

                counterInMaster++;

                if(counterInMaster >

25

){

                    counterInMaster =

0

;                

                    stringBuffer[

26

] = '

\0

';

                    send2Usart2(stringBuffer);                

                    }        

            }

    }   0690X00000603aBQAQ.jpg

---------------------------------------------------------------?

S.Ma
Principal
Posted on January 28, 2017 at 17:10

Hmm, my two cents quick look at it: master or slave mode RXNE and TXE won't come simultaneously.

TXE is set before the master sends say 8 SPI.SCK clock bit periods through the bus... RXNE will pop once all clock bits went through the SPI bus and a full byte has been received. If both are set it means timing issues.

A direct write to USART from SPI Slave means the bitrate of the USART (including Start, Stop, parity if any) is fast enough for the job. A better scheme would be to put a SW FIFO between the SPI incoming data and the USART TX. If the SW FIFO overflows, you can catch errors and size the FIFO to smooth the flow and guarantee no loss of data.

Similar analogy was CD Players with FIFO between optics and speakers to take care of 'bumps'...

Making sense?

M N
Associate II
Posted on January 28, 2017 at 20:03

Thank you . I took your point . But there is something else here that i can't understand. If my procedure is wrong why in first program it works fine (when i put 0xFF in tx slave buffer ) and when i put any other letter or character in Slave Buffer data will corrupt ?

And i tried other program ( A lot i mean. I'll put one of them below ) for example I sent some data from Master and in Slave side just send character 'A' .When transferring data from Master to Slave has finished i disabled interrupt and after that sent data to UART but the problem still exists...↓

-------------------------Problem still exists ------------------------------↓

void

SPI2_IRQHandler(

void

){

            if( SPI2->SR & SPI_SR_TXE ){

                SPI2->DR =

0x41

; // �

any character lead to corrupting data

 

            }

            if( SPI2->SR & SPI_SR_RXNE ){

                stringBuffer[counterInMaster] = SPI2->DR;

                counterInMaster++;

                if(counterInMaster >

25

){

                    

SPI1->CR2 &= 0<<7;

// Disable Master interrupt source TXEIE

                    

SPI1->CR2 &= 0<<6;

// Disable Master interrupt source RXNEIE // so this part run one time and UART                      rate it's not importanat any more ;

                    counterInMaster =

0

;                

                    stringBuffer[

26

] = '

\0

';

                    send2Usart2(stringBuffer);                

                    }        

            }

    }  

-------------------------------------------------------↑

So how you guys write full duplex transferring with CMSIS and your data won't corrupt ?

Posted on January 29, 2017 at 08:41

Various guesses: One of the SPI device is in bidir mode, 3 wire mode or open drain (AND-wired logic by open drain). In this case, if you send 0x00 you would only see 0x00 out there. Look and check at the GPIO configuration both slave and master side.

While not important here, pushing a string to USART within an interrupt make me wonder... interrupts are deemed to be short in time to only deal with latency. How the USART is being used (polling?) while within an interrupt might takes lots of time. 

Posted on January 29, 2017 at 11:38

Which devices are you using for master and slave? What is the clock frequency? How long is the interconnection? Do you have good consistent common ground? Do you have waveforms of both data lines and clock captured by an oscilloscope or logic analyzer, to show us?

Post minimal but complete compilable code which exhibits the problem, for both master and slave.

JW

M N
Associate II
Posted on January 29, 2017 at 11:26

Both are config in full duplex . Both has same configuration in pin or other configuration just one of them is Master and the other one is Slave . If i send 0x00 or any thing else slave will receive it , Until i don't write any letter or character to Slave Tx buffer . 

The meaning and reason of Interrupt or Polling is not important here . As i write another program below this post that i disabled interrupt and send data to USART so it's not any more important we are in interrupt because we are in polling mode after disabling .

My question is why data is Ok when i write 0xFF or 0x00 in Data Register in Tx buffer empty time in Slave but will corrupt when ill write any other character ? i want to write data to tx buffer and transmit it when data is coming from master but it won't work !? how can i do this ?

Posted on January 29, 2017 at 16:44

 ,

 ,

I'm using STM32F407 and Both Master and Slave are in one MCU ( but i test it on two board also ).

I've tested different clock frequency (fpclk/2 ....fpclk/256).And interconnection is not too long because both spi are in same microcontroller in one board . Ground is Ok.Unfortunately i do not have oscilloscope or logic analyzer.

the code is :↓

(this code works good and send alphabetic from Master to Slave and the Slave send it to UART and i can see the result good .But if i change the Red Line Below by sending any other character data will corrupt .)

♯ include

'stm32f4xx.h'

 ,

void

send2Usart2(__IO

char

* data),

 ,

♯ define

True 1

__IO

char

counter =

0x41

,

__IO

char

stringBuffer[

28

],

 , , ,

//SPI1 handler-----------1-----------

 ,

 , ,  ,

void

SPI1_IRQHandler(

void

){

 ,

 , ,  , , ,  , , ,  , , ,  ,uint8_t tempData ,

 ,

 , ,  , , ,  , , ,  , , ,  ,

if

( SPI1->,SR &, SPI_SR_RXNE , ){ , ,  , , ,  , , ,  , , ,  , , ,  ,

 ,

 , ,  , , ,  , , ,  , , ,  ,tempData = SPI1->,DR,

//this line do nothing just for clearing TXNE Flag

 ,

 , ,  , , ,  , , ,  , , ,  ,}

 ,

 , ,  , , ,  , , ,  , , ,  ,

if

( SPI1->,SR &, SPI_SR_TXE ){

 ,

 , ,  , , ,  , , ,  , , ,  ,SPI1->,DR = counter,

 ,

 , ,  , , ,  , , ,  , , ,  ,counter++,

 ,

 , ,  , , ,  , , ,  , , ,

 ,if

(counter >,

0x5A

)counter=

0x41

,

 ,

 , ,  , , ,  , , ,  ,}

 ,

 , ,  ,}

//SPI2 handler------------2----------

 ,

 , ,  ,

void

SPI2_IRQHandler(

void

){

 ,

 , ,  , , ,  , , ,  , , ,  ,uint8_t tempData ,

 ,

 , ,  , , ,  , , ,  , , ,  ,

static

uint32_t counterSlave =

0

,

 ,

 , ,  , , ,  , , ,  ,

if

( SPI2->,SR &, SPI_SR_TXE ){

 ,

 , ,  , , ,  , , ,  , , ,  ,

SPI2->,DR = 0xFF, // � data will corrupt if i change this character to something else i.e 0x41

 ,

 , ,  , , ,  , , ,  ,}

 ,

 , ,  , , ,  , , ,

 ,if

( SPI2->,SR &, SPI_SR_RXNE ){

 ,

 , ,  , , ,  , , ,  , , ,  ,stringBuffer[counterSlave ] = SPI2->,DR,

 ,

 , ,  , , ,  , , ,  , , , , counterSlave++,

 ,

 , ,  , , ,  , , ,  , , ,  ,if(counterSlave >,

25

){

 ,

 , ,  , , ,  , , ,  , , ,  , , , , counterSlave =

0

, , ,  , , ,  , , ,  , , ,  , , ,

 ,

 , ,  , , ,  , , ,  , , ,  , , ,  ,stringBuffer[

26

] = '

\0

',

 ,

 , ,  , , ,  , , ,  , , ,  , , ,  ,send2Usart2(stringBuffer), , ,  , , ,  , , ,  , , ,  , , , ,

 ,

 , ,  , , ,  , , ,  , , ,  , , ,  ,} , ,  ,

 ,

 , ,  , , ,  , , ,  ,}

 ,

 , ,  , , ,  ,} , , ,

//// other code ↓

int main( void) {

 , , , RCC->,AHB1ENR |=RCC_AHB1ENR_GPIOAEN,

//SPI_AND_UART

 ,

 , ,  ,RCC->,APB1ENR |=RCC_APB1ENR_USART2EN,

 ,

 , ,  ,RCC->,AHB1ENR |=RCC_AHB1ENR_GPIOBEN,

//SPI

 ,

 , ,  ,RCC->,APB1ENR |=RCC_APB1ENR_SPI2EN,

//SPI

 ,

 , ,  ,RCC->,APB2ENR |=RCC_APB2ENR_SPI1EN,

//SPI

//Pin

 , , ,GPIOA->,MODER |=

0x00A0

,

//UART

 ,

 , ,  ,GPIOA->,OSPEEDR |=

0x00A0

,

//UART

 ,

 , ,  ,GPIOA->,AFR[

0

]|=

0x7700

,

//UART

 ,

 , ,  ,

 ,

 , ,  ,GPIOA->,MODER |=

0xAA00

,

//SPI1

 ,

 , ,  ,GPIOA->,OSPEEDR |=

0xFF00

,

//SPI1

 ,

 , ,  ,GPIOA->,AFR[

0

]|=

0x55550000

,

//SPI1

 ,

 , ,  ,

 ,

 , ,  ,GPIOB->,MODER |=

0xAA000000

,

//SPI2

 ,

 , ,  ,GPIOB->,OSPEEDR |=

0xFF000000

,

//SPI2

 ,

 , ,  ,GPIOB->,AFR[1]|=

0x55550000

,

//SPI2

//Configuration SPI2 _ Slave

 , , , SPI2->,CR1 =

0x00000030

,

//SPI2_ADDED_Slave_FPCLK/16 (The frequency in Slave is not important 42/16 = 2.625)

 , , , SPI2->,CR1 |=

0x00000001

,

//clock phase (has changed for test)

 , , , SPI2->,CR2 =

0x000000C0

,

//SPI2_Slave_RXNEIE_TXEIE

 ,

 , ,  ,SPI2->,CR1 |=

0x00000040

,

//Enable_SPI

//Configuration SPI1 _Master

 , , , SPI1->,CR1 =

0x00000024

,

//SPI1_ADDED_Master_FPCLK/32 ( 84/32 = 2.625)

 ,

 , ,  ,SPI1->,CR1 |=

0x00000001

,

//clock phase (has changed for test)

 , , , SPI1->,CR2 =

0x000000C4

,

//SPI1_Master_TXEIE_RXNEIE__SSOE-Enable

 ,

 , ,  ,SPI1->,CR1 |=

0x00000040

,

//Enable_SPI

//Configuration UART_AND_NVIC

 , , , , , ,USART2->,CR1 =

0x200C

,

//USART_TX_RX

 , , , , , ,USART2->,BRR =

0X1117

,

 , , , , , , NVIC_EnableIRQ(USART2_IRQn),

 ,

 , ,  , , , ,NVIC_EnableIRQ(SPI2_IRQn),

 ,

 , ,  , , , ,NVIC_EnableIRQ(SPI1_IRQn),

while

(True){ }

//while_end ,

}

//main_end

void

send2Usart2(__IO

char

* data){

 , ,  ,USART2->,DR =

'*'

,

 ,

 , ,  ,

while

( (USART2->,SR &, USART_SR_TXE) ==

0

),

 ,

 , ,  ,

while

(*data!=

'\0'

){

 ,

 , ,  ,USART2->,DR = *data,

 ,

 , ,  ,

while

( (USART2->,SR &, USART_SR_TXE) ==

0

),

 ,

 , ,  ,data++,

 ,

 , ,}

 ,

 ,}
Posted on January 29, 2017 at 23:16

Huh.

Try to:

- initializemaster SPI first - otherwise the lines are floating while the slave is already initialized thus might pick up spurious clocks

- decrease speed setting in OSPEEDR - the 25MHz should be enough

- set realterm to display hex and post what's those 'incorrectly received' bytes

I admit I have no explanation why changing data transmitted by slave should matter.

Style advices:

Don't use magic constants, it's a considerable effort to decipher them. Instead, use the device header defined constants throughout. You might want to define the non-single-bit bitfield values ST don't define. E.g. I use

#define  DMA_SIZE__BYTE            0

#define  DMA_SIZE__HALFWORD        1

#define  DMA_SIZE__WORD            2

#define  DMA_PRIORITY__LOW         0

#define  DMA_PRIORITY__MEDIUM      1

#define  DMA_PRIORITY__HIGH        2

#define  DMA_PRIORITY__VERY_HIGH   3

#define  DMA_DIR__P2M              0

#define  DMA_DIR__M2P              1

[...]

      DMA1_Channel3->CMAR  = (uint32_t)redLedTable;

      DMA1_Channel3->CPAR  = (uint32_t)&LPTIM1->CMP;

      DMA1_Channel3->CNDTR = sizeof(redLedTable) / sizeof(redLedTable[0]);

      DMA1_Channel3->CCR   = 0

        | ( 1 *                  DMA_CCR_EN      )    // Channel enable

        | ( 0 *                  DMA_CCR_TCIE    )    // Transfer complete interrupt enable

        | ( 0 *                  DMA_CCR_HTIE    )    // Half Transfer interrupt enable

        | ( 0 *                  DMA_CCR_TEIE    )    // Transfer error interrupt enable

        | ( DMA_DIR__M2P *       DMA_CCR_DIR     )    // Data transfer direction

        | ( 1 *                  DMA_CCR_CIRC    )    // Circular mode

        | ( 0 *                  DMA_CCR_PINC    )    // Peripheral increment mode

        | ( 1 *                  DMA_CCR_MINC    )    // Memory increment mode

        | ( DMA_SIZE__HALFWORD * DMA_CCR_PSIZE_0 )    // PSIZE[1:0] bits (Peripheral size)

        | ( DMA_SIZE__HALFWORD * DMA_CCR_MSIZE_0 )    // MSIZE[1:0] bits (Memory size)

        | ( DMA_PRIORITY__LOW *  DMA_CCR_PL_0    )    // PL[1:0] bits(Channel Priority level)

        | ( 0 *                  DMA_CCR_MEM2MEM )    // Memory to memory mode

      ;

You get the point.

Don't do anything which would hold up ISR, here, USART transmission.

JW

Posted on January 30, 2017 at 00:48

Thaaaank you ?. after 8 days .now it works.

About ''Style advices''.Consider it done ,and thank you for your advice (It was easy to writing for me but yes I agree It's hard to read in that way ) But I will change it to your style advice .

About the ISR , I know it is not good to do heavy process . But i need to see the result and i do not have oscilloscope or logic analyzer so i choose this way or set flag in ISR and do stuff in while loop  ( debug is not good always).But in final project usually I use Flag set or reset in ISR .

Now It's the result : ?

0690X00000603WKQAY.jpg

Decreasing speed

setting in OSPEEDR has worked .! How did you know that ? I read reference manual a lot and very carefully (i tried) . But i didn't realize that point.