cancel
Showing results for 
Search instead for 
Did you mean: 

spi interrupt problem for lsm330dl

mengsophia
Associate II
Posted on July 09, 2012 at 12:33

i try to use the spi interrupt , but the whole program just hanged at case 101 which is in the void GYRO_Task(void),  it shows me ''+++''. anything wrong?

here is some part of my code.

 #ifdef GYRO_SPI_USE_INTERRUPT

    NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

 #endif 

void GYRO_Trigger_Read(uint16_t HalfWord, unsigned char *rxdataptr)

{

 HalfWord = HalfWord << 8;

 HalfWord |= 0x8000;

 GYRO_TxData = HalfWord;

 GYRO_RxDataPtr = rxdataptr; 

#ifdef GYRO_SPI_USE_INTERRUPT

 SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_TXE, ENABLE);

 SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_RXNE, ENABLE);

#endif

 GYRO_CS_LOW();   

}

void GYRO_Interrupt_SetRxData(unsigned char tempchar)

{

 *GYRO_RxDataPtr = tempchar;

 GYRO_Operation_State = 0;

}

char GYRO_Interrupt_GetTxData(void)

{

 return GYRO_TxData;

}
9 REPLIES 9
frankmeyer9
Associate II
Posted on July 10, 2012 at 09:42

What is your SPI interrupt handler function ?

 SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_TXE, ENABLE);

 

 SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_RXNE, ENABLE);

 

Do you clear all pending SPI interrupts in this handler ?

If not,  your code might turn endless inside the SPI interrupt handler.

mengsophia
Associate II
Posted on July 10, 2012 at 11:55

void SPI2_IRQHandler(void)

{

 //  GYRO_CS_LOW();

   if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_TXE) != RESET)

  {

    SPI_I2S_SendData(SPI2, GYRO_Interrupt_GetTxData());

 SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_TXE, DISABLE);

  }

   if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET)

  {         

     GYRO_Interrupt_SetRxData(SPI_I2S_ReceiveData(SPI2));

  SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_RXNE, DISABLE);

  }

  

  GYRO_CS_HIGH(); 

 

i did close the interrupt in this function.

but my output is very strange. it can't jump to the next case. and the value i got is always FF.

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

GYRO_XH [ffffffff]

frankmeyer9
Associate II
Posted on July 10, 2012 at 13:59

Is it possible that you understood something wrong here ?

 ...

  SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_RXNE, DISABLE);

 

  ...

This does not acknowledge a pending interrupt, but disable the interrupt alltogether.

You never again get a SPI_RXNE interrupt until you explicitely reenable it.

The RXNE interrupts does not need special treatment. It is acknowledged (i.e., the interrupt-pending-flag is cleared) by a read access to the DR register.

The TXE interrupt-pending-flag is cleared by a write access to DR.

So there is no need to disable the interrupts, unless you really want to stop sending/ receiving.

mengsophia
Associate II
Posted on July 11, 2012 at 03:34

but if i don't disable the interrupt, the program will just hang there, i can see it keeps looping at case101, and can't enter the interrupt. that's why i add the disable sentance.

actually there isn't any wire connect the gyro interrupt register to the cpu. i just wanna use the spi intrrupt to escape the while loop in the read function, during that time the cpu can't do any other things.

another thing is that i did reable the interrupt in the GYRO_Trigger_Read(). i actually use it to replace the old read function. i attached my code.

i put some printf sentance inside the interrupt service function, it shows that i did enter the interrupt. but why the output data looks no meaning at all.

________________

Attachments :

7.11.txt : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HtWN&d=%2Fa%2F0X0000000aRD%2FmCsCCOLNsDQH7bfs2Zeqi9ZWskGKyQenxvBhxWmIpXQ&asPdf=false
frankmeyer9
Associate II
Posted on July 11, 2012 at 08:39

I would have the code organized differently - please note this is also a matter of style.

First, if I required an equidistant sampling of accelerometer/gyro data, I would rely on the timing of the device, i.e. use the corresponding interrupts. One could also use an internal timer, but this hardly synchronizes to the acc/gyro sampling.

Second, I would have organized the readout and evaluation on packages, not single bytes. With package I mean three 16-bit words for X,Y an Z, which represent one acc or gyro datapoint..

I would have started a readout (upon what event you choose) with enabling the SPI interrupts and writing the first byte. The rest of this package is handled inside the interrupt routine, where the SPI interrupt is finally disabled after the last byte of the package (6 bytes).

I then would have to evaluate this package in some state machine like you are doing now.

But IMHO, handling single bytes inside this state machine makes it quite complex and hard to read/understand.

mengsophia
Associate II
Posted on July 12, 2012 at 10:52

i try to use buffer, but what i received is 00, anything wrong? 

#define BufferSize 6

u16 SPI2_Buffer_Tx[BufferSize] = {0xA900, 0xA800, 0xAB00, 0xAA00, 0xAD00, 0xAC00};

void SPI2_IRQHandler(void)

{

   if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_TXE) != RESET)

  {

 SPI_I2S_SendData(SPI2, SPI2_Buffer_Tx[TxIdx++]);

 if (TxIdx == BufferSize)

    {

      SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_TXE, DISABLE);

    }

  }

   if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET)

  {  

    SPI2_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI2); 

 printf(''\r\n SPI [%x] '',SPI2_Buffer_Rx[RxIdx++]);

 SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_RXNE, DISABLE);

  }

  

  GYRO_CS_HIGH(); 

}

frankmeyer9
Associate II
Posted on July 12, 2012 at 11:40

if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET)

{

 

    SPI2_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI2); 

 

    printf(''\r\n SPI [%x] '',SPI2_Buffer_Rx[RxIdx++]);

 

    SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_RXNE, DISABLE);

 

}

Possibly this - I believe it's a Copy&Paste error.

If I get it right, you advance the buffer pointer to the next free position after reception, and the following printf() peeks a zero value, advancing the buffer pointer yet again.

I see two possible problems:

 - you might exceed you buffer size boundary

 - I would avoid printf() in interrupt handlers; they involve lib calls that distort the timing

mengsophia
Associate II
Posted on July 16, 2012 at 09:58

i still don't underatand what's wrong with my code. i've tried many ways .but still can't get correct output value. could u show me some working code for referring?

by the way i think it's ok to write printf ()in the interrupt.

frankmeyer9
Associate II
Posted on July 16, 2012 at 13:59

I see another problem with your code:

#define BufferSize 6

u16 SPI2_Buffer_Tx[BufferSize] = {0xA900, 0xA800, 0xAB00, 0xAA00, 0xAD00, 0xAC00};

void  SPI2_IRQHandler (void)

{

  if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_TXE) != RESET)

  {

    SPI_I2S_SendData(SPI2, SPI2_Buffer_Tx[TxIdx++]);

    if (TxIdx == BufferSize)

    {

      SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_TXE, DISABLE);

    }

  }

  if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET)

  {

    SPI2_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI2);

    printf(''\r\n SPI [%x] '',SPI2_Buffer_Rx[RxIdx++]);

    SPI_I2S_ITConfig(GYRO_SPI, SPI_I2S_IT_RXNE, DISABLE);

  }

  GYRO_CS_HIGH();

}

If this is still the code in use.

    SPI2_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI2);

This code does not do what you probably intend

(I found no declaration of SPI2_Buffer_Rx[] in your code, but as the SPI2_Buffer_Tx[] declaration induces, it is uint16_t).

The call toSPI_I2S_ReceiveData()  returns 16 Bit data, but actually contain byte-sized data, according to tha lsm330 data sheet. And with RxIdx++, you advance the index not by one byte, but by one element, i.e. 16 bit (uin16_t).

> by the way i think it's ok to write printf ()in the interrupt.

 

It might be o.k., or not, depending on your type of application, and the interrupt priorities.

I guess you have a hosted or semi-hosted application, meaning your printf output appears on the host. It will certainly take some time to get these printf() data out, usually longer than receiving an SPI frame. With unfavourable interrupt priorities, you might lose SPI data (rather not, as your uC is the SPI master), or get out of sync with the gyro, i.e. your xyz data are not belonging to one sample time anymore.

I would do a printf when all data (y,x,z) are available.

> could u show me some working code for referring?

 

I do not have a LSM330, so I'm not in possession of such a proven, working code - sorry.

I have examples for similiar sensors (LIS302, IMU300), but based on I2C, not SPI.

But as a working example, you can study the STM32F4_Discovery firmware.

This board has a LIS302 (accelerometer only), and the firmware source contains SPI based sample code.