Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Nested Interrupts on STM8


  • Please log in to reply
5 replies to this topic

#1 ByteMaster

ByteMaster

    Advanced Member

  • Members
  • PipPipPip
  • 76 posts

Posted 09 June 2012 - 02:31 PM

I'm doing some testing on one of my modules and it's dropping bytes that are sent back to the GO! mainboard via SPI.

Let's say I want to send the following byte array
0x12 0x34 0x45 0x56

What's getting sent back via SPI is:
0x12 0x34 0x34 0x56

I think I've tracked this down the SPI IRQ not being serviced in time to queue up the next byte to be sent.

In addition, from what I can tell this is happening because I'm measuring pulse width on a GPIO interrupt (long story, but can't use built in timer to measure PWM).

From review of the data sheets, I had though I could set the SPI Interrupt to be a priority so it would get called within the GPIO interrupt but it doesn't seem to be working.

ITC->ISPR3 &= 0xDF;

Which should set the VECT10SPR = 01 which would be a Level 1 priority which in turn should let the SPI IRQ interrupt the GPIO IRQ and queue up the next character, (SPI is Interrupt vector 10).

I'm fairly certain I could solve this by moving into the 32 bit world and DMA, but I'm just not ready to make that jump yet :huh: beside, I'm pretty sure this should work. I'm currently using an STM8S207K6

Any thoughts? What am I'm issing?

Kevin...
Kevin D. Wolf
Windows Phone Development MVP
President Software Logistics, LLC
Tampa, FL

#2 Matt Isenhower

Matt Isenhower

    Advanced Member

  • Members
  • PipPipPip
  • 74 posts
  • LocationSan Diego, CA

Posted 09 June 2012 - 05:01 PM

Hi Kevin, I think you have the right idea with setting other interrupts to a lower priority -- this is what I'm doing on my seven segment display module to handle the display multiplexing from a timer. The problem is that you need to set the priority level of the other interrupts you're using rather than the priority of the SPI interrupt. All interrupts start out at the highest priority level, 3. As soon as one interrupt is set to a lower priority level, the interrupt handling is switched to nested mode and you can start getting interrupts during other interrupt service routines. Try setting your other interrupt(s) to a lower priority to see if that fixes the problem. In my code, I'm using level 2 (which is actually set with 0 and 0 written to the priority level bits) for the multiplexing timer and that seems to work perfectly. Just leave the SPI interrupt vector at its default level 3 and it should take priority over everything else. If you have a logic analyzer and a few extra pins, you can actually visualize when your interrupts are being serviced by setting a different output pin high when each interrupt is being handled and setting it low when it's done. That will let you verify that your interrupts are being nested properly without much interference (unlike setting breakpoints, etc.). Oh -- one other thing. If you are connected with the debugger, you can actually view and modify the peripheral registers while the program is executing to see how its behavior changes. In IAR (and I think also STVD) you can actually change the content of these registers without pausing program execution, so you can quickly see how changing the different priority levels (or any other setting) effects execution in real time. Let me know how it goes! Matt
Komodex Labs
Follow me on Twitter: @mattisenhower

#3 ByteMaster

ByteMaster

    Advanced Member

  • Members
  • PipPipPip
  • 76 posts

Posted 09 June 2012 - 11:01 PM

Hi Mark - Thank you very much for your response!

DOH! I read the priority bits backwards...for some reason I thought a lower number meant higher priority!

Try setting your other interrupt(s) to a lower priority to see if that fixes the problem. In my code,


Saying that, my first attempt didn't resolve the issue :(. I'll have to play with it a bit more tomorrow.

In the “real-world usage” of the app, it fails very intermittently, about one out of 50 transmissions are garbled, if I just extend the time in the GPIO handler with something like:
//Spin for a while in my IRQ
u16 count = 0x1FF;
while(count-- > 0);

It fails most of the time.

As another test if I do the following in my GPIO handler:
//Spin for a while in my IRQ
u16 count = 0x1;
while(count-- > 0);

There are no corrupted messages, so this really leads me to believe that the time in the GPIO handler is my issue and if I could bounce into the SPI handler life would be good!

Although I don’t have any hard metrics, it seems like about 1 out of 50 transmissions were corrupted before changing the GPIOD IRQ priority, after it seemed like it might have been about 1 out of 200…not sure if that makes sense?!??! I would almost expect it to work…or not.

Oh well, I was being lazy and guess either way I should probably introduce a CRC byte at the end of the transmission.

Kevin…
Kevin D. Wolf
Windows Phone Development MVP
President Software Logistics, LLC
Tampa, FL

#4 Matt Isenhower

Matt Isenhower

    Advanced Member

  • Members
  • PipPipPip
  • 74 posts
  • LocationSan Diego, CA

Posted 10 June 2012 - 05:24 AM

The SPI timing is fairly tight but, for the most part, if you make sure your SPI ISR is as fast as possible you should be in pretty good shape. I did notice that some of the functions in the ST standard peripheral libraries were considerably slower than accessing the registers directly, and in some cases, slow enough to make a difference (although that could have been due to other issues in my code at the time). If you look at the source code for the peripheral libraries that will give you a head start for accessing the registers directly, and you'll find that there is a lot of input/error checking code that you can simply leave out, which definitely helps speed things up. I don't recall if you said you had a logic analyzer but that can really help with debugging as well. Very useful to make sure what you intended to send actually got sent :) plus it's really the best way to make sure your interrupts are nesting properly. Sending a CRC byte will help, but since the hardware is what calculates the CRC value it's based on what was actually transmitted over the line, which may not be the same as what you intended to transmit. You could calculate the outgoing CRC byte yourself, but that may be too slow to be useful (I haven't actually tried doing that). One tip about using the hardware CRC transmission: you may want to disable the SPI TXNE interrupt when you tell it to transmit the CRC byte next. Otherwise, the TX buffer is still technically empty and the SPI TXNE interrupt will be constantly raised until the message has been completed (or until you set the TX buffer). You just need to make sure you re-enable the TXNE interrupt before the next message begins.
Komodex Labs
Follow me on Twitter: @mattisenhower

#5 Nevyn

Nevyn

    Advanced Member

  • Members
  • PipPipPip
  • 1072 posts
  • LocationNorth Yorkshire, UK

Posted 10 June 2012 - 03:32 PM

The SPI timing is fairly tight but, for the most part, if you make sure your SPI ISR is as fast as possible you should be in pretty good shape. I did notice that some of the functions in the ST standard peripheral libraries were considerably slower than accessing the registers directly, and in some cases, slow enough to make a difference (although that could have been due to other issues in my code at the time). If you look at the source code for the peripheral libraries that will give you a head start for accessing the registers directly, and you'll find that there is a lot of input/error checking code that you can simply leave out, which definitely helps speed things up.

This is where I started - using the standard library for the main code - initialisation and stuff but I access the registers directly inside my ISRs.

Having said that, I spent a day of time over three/four days debugging a problem which finally turned out to be a problem with the standard libraries (I had a rant here). As a result I have now abandoned the standard libraries and now work with the registers directly.

Regards,
Mark

To be or not to be = 0xFF

 

Blogging about Netduino, .NET, STM8S and STM32 and generally waffling on about life

Follow @nevynuk on Twitter


#6 ByteMaster

ByteMaster

    Advanced Member

  • Members
  • PipPipPip
  • 76 posts

Posted 16 June 2012 - 02:57 PM

Well guess, I need to chalk this one up as a learning experience.

I was doing all my work in the RXNE (receive buffer not empty) handler for SPI. As soon as I moved my sending code to a TXE (transmit buffer empty) handler it seems like everything is working great.

So bascially in my previous interrupt handler, I needed to do all my work in the one clock cycle between the byte finishing up coming down from MOSI and the next byte coming in, this was just a few micro seconds and the timing was too tight to have it work reliably

With the working approach -
I receive the first character from the master, then when I queue up the next byte to be sent, enable the TXE SPI interrupt. Then as soon as the transmit buffer is empty (which looks like about 25% through the transmission, the TXE SPI IRQ will fire and I can queue up the next byte to be spent with plenty of time to spare. Then when I know I'm done sending data, I just need to disable the SPI TXE IRQ.

Then first thing in my handler I have code to figure out what needs to happen:
	if(SPI->SR & 0x01)
		GO_ProcessByte(SPI_ReceiveData());
	else if(SPI->SR & 0x02)
		GO_HandleTxe();

So far it seems to work.
Kevin D. Wolf
Windows Phone Development MVP
President Software Logistics, LLC
Tampa, FL




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.