SPI access sharing between ISR and main - AT45, AT25, others

Go To Last Post
22 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,
The software I wrote is quite complex, but I have encountered the following issue that makes programming very complex. This is a sort of warning of unexpected complexity. I would welcome any recommendations how to circumvent the problem.

In my application, I use SCP1000 SPI sensor. He is raising specific line periodially (DRDY), after this I have VERY SHORT period of time to read its register via SPI.
Everything is fine, until:
at the same time, serial flash and eeprom AT45 and AT25 are often accessed. One is 2MHz mode 0,0 another something else, and SCP1000 is mode 1,1 0.5MHz (or anything else, this is a general problem).
The trick is, when DRDY is raised by SCP1000 while CS is already high for AT45, in the ISR servicing the SCP1000 I have to: lower the CS of the AT45 (an this is hell of mess since there are 6 other things on the SPI), setup SPI, comm with SCP1000 then restore SPI state for AT45. The only trick is, AT45 is aborting 'continuous read' or 'continuous write' operation after CS is raised (by design of the chip: in order to protect the data). So there is one more solution: use cli() and sei() pairs around 'casual, blocking' SPI accesses. But this time, the time to read the whole chunk of data from AT45 is so long, while I cannot go into ISR in order to service SCP1000 on time.
General impression is that:
1. it is good to have 2 SPI interfaces, one for realtime, one for offline/blocking transactions.
2. the feature from AT91SAM7A3 that has special hardware module that excludes multiple CS lines to be active simultaneously would simplify the code considerably
3. When some devices need low-delay access via SPI (typically hi-tech digital sensors), they disallow the optimal use of serial flashes because the comms with eeproms must be done in pairs 'sigle address, few data' instead of 'address, data streeeeeeeeeam'.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

1. it is good to have 2 SPI interfaces, one for realtime, one for offline/blocking transactions.

I do not disagree that this may be a good approach. But define

Quote:

VERY SHORT period of time

I assume that means longer than a bulk transfer to/from one of the memories. But 1us? 100us? 1ms? 10ms?

Anyway, most new generation ATmegas have the feature of a USART as SPI master. So twin SPIs might make a lot of sense.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Time to service DRDY is some 1ms, but this is nothing to bulk transfer that takes 100+ms. So in theory I can break the transfer, do the bookkeeping, communicate with SCP1000 etc but this is a very messy code (the efficiency might be fine since DRDY fores interrupt at some 8Hz, so resending the read addr to serial eeprom 8 tiems per second is not the issue, the problem is that I cannot make it cleanly).
USART as SPI master sounds good. I forgot the opportunity But because I also need 2 separate USARTS for long range (2m) communication, I need to go for ATMEGA1280. This means more difficulties with soldering by hand. Anyway I am running low on ATMEGA resources here. This is a pity since normally I don't want ARM7's interrupt latency, also don't need its firepower (also prefer to stay around 40mA @5V, need 5V ADC etc).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After reading the specifications for the SCP1000, it appears as if the data rate is relatively slow, 1HZ, 1.8HZ or 9HZ. If you know what data rate the device is programmed for, once you get a DRDY, you know how long it will be before the next pressure data is ready to be read. If possible, plan other SPI events (schedule) in between pressure readings so that timing conflicts don't occur.

Since the SPI is shared among several devices, a timing diagram would help define shared bus usage. A careful timing study may show that you have plenty of time for everyone and no conflicts.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I need the fastest possible update rate from SCP1000. This is why I am using continuous mode. This means its ~8Hz readings fall anywhere, while the main loop is really hard realtime at 32Hz with several PID branches.
On top of that, every 1s or so the 516bytes of log are written and are ready to be flashed to AT45. So you see I want to marry maximum sensor bandwidh with hard realtime requirement plus code robustness if God permits.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you really need another SPI module? Implementing SPI in software through bit-banging is not that difficult when you are the master. If you have the port pins available just bit-bang to the pressure sensor since the data rate is slow and the amount of data is much less than with your Flash.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bit-banging tends to worsen interrupt latency since you need to put _delay_us(X) inside cli()...sei() somewhere, or eventually you overuse your timers and make some scary state machine.
I don't want to throw in (one day) magnetometer just to conclude it has similar requirements on time of servicing, this time unable to fulfill it because the SCP1000 could be bitbanging at the same time, even if on different set of pins (this time SCP1000 would block by cli/sei its own part). Or maybe I should think more about bitbanging.
But, I really, really want to stay with hardware solutions, also because all I have now free at ATMEGA128 are 8 IO pins. The project grew really fat.
Miraculously it fits 50x120mm PCB with components sticking 5mm to each other on both sides. There are 2 atmegas, 6 slave SPI toys, 3 TWI slaves, 3 USART things including FTDI, all PWM output channels used, all ADC used, all timers used, all external interrupt pins used, a lot of floating point calc running around. I dont want to mix it up with bitbanging. I am evalutaing future migration paths and possible future hardware solutions.

Last Edited: Tue. Nov 11, 2008 - 09:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another (still hazy) idea would be to use TWI version of SCP1000 since you can hold clock for a long time on I2C.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

At an 8HZ sensor rate, that is 125mS between sensor readings.

Not counting overhead, writing 516 bytes to AT45 at 2MHZ SPI = (1/2MHZ x 8 x 516) + 14mS ~= 16mS.

Remember, your 8HZ sensor readings won't "fall anywhere". They will occur approximately 125mS from the last one. If you sync your housekeeping/data logging tasks to the DRDY signal, and you can get your other main tasks complete in 125mS, you won't run into conflicts.

Given the constraits that you've described, it seems like there is sufficient time.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"approximately 125mS"
... and this appears to change with the value being read and temperature. very funny behaviour.

Well basically you are 100% right.
My SCP1000 is async 8Hz now, but rescheduling it in such a manner so it wont collide with logger that occurs at (variable) ~0.75Hz on 32Hz grid, it won't collide.
There are no uOS inside, so at the end logger code should be SCP1000 aware, or SCP1000 should be made logger aware, that's all, but this is what make me unhappy. I wanted some clean solution.

Last Edited: Tue. Nov 11, 2008 - 09:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

8Hz is an eternity in AVR time. "As soon as possible" is still then >100ms; I wouldn't see how a ms one way or another would matter to the app "closing the loop"--I assume that's what you are doing.

Lessee--if you run an external interrupt off the data ready signal and bit-bang the 16-bit register read, 24 bit packet, inside the ISR, how long will we hang there? The max SPI clock rate is 1MHz so you will need to be careful to space the bits but by the time you shift the 16-bit output "register" and read the bit and set the low bit accordingly, it shouldn't be too painful. Let's say we burn 2us/bit, or 50us total to service the interrupt.

How would that affect other communications? The "real" SPI work won't even care. USART comms at 115kbps is about 100us/character, so no danger of a miss there--since the pressure sensor won't interrupt for another 100ms the USART can easily catch up.

I guess I'd then vote for a Mega164 family with twin USARTs, hardware SPI, and bit-bang the repetitive pressure reads inside the event ISR.

Side note: I haven't used them, but have read through the Atmel AT90SAM7S docs and I thought that they had implemented a fast interrupt mechanism that was on a par in response to the AVR. yeah--the FIQ Fast Interrupt reQuest.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Once again the main timeline ticks at 32Hz with LOADS of code. Ther are interrupts around that are tiny and come via TWI, USARTS, timers etc.
The trick is that there is SPI1000 at variable 8Hz framerate, SLOWER than main 32Hz loop. this SCP is async and left as such, I see no point triggering SCP 'maually' so it will start every 5th main tick because the reading might be ready anywhere during main loop, 4 to 5 main loops later. At the same time, the log makes long write every 4-6 main loops, it heas its own timeshare, no hard realtime violation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch, bitbanging=interesting, I should think more about the numbers before naysaying.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"Maximum time for servicing the DRDY interrupt 55ms"
I am sure I have a bug somwhere, in my system it looks like 5ms at best.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

"Maximum time for servicing the DRDY interrupt 55ms"

Remember that just means that is when the next temperature reading is updated. In theory you have 100ms+ to read the pressure, as I read the datasheet.

But in any case, those are ms, and even with some latency other methods are in us. In fact, I can't see where a 100ms lag would necessarily bother you, since you can recover anyway.

The choice of an expensive US$50+ pressure sensor is interesting in itself. Do you really need the full resolution? Amplified sensors with analog out should be in that range or less. Or you can always make your own from sensor element and amplifier.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I need ultra small footprint and 16-17 bit resolution for altitude stabilisation. My country allows for unregistered operation max 30kg airplane and 150m AGL max flight level, max airspeed limited by GPS to negligible 800MPH, within eye of sight, out of city limits, 2.4GHz datalink up to 10mW. The best thing that fits those laws is short range amateur cruise missile, ZERO electromagnetic emmision (must drop the idea of altitude sensing radar, but the country is hopefully flat). The blast and cloud after impact satisfies 'within visual range' requirement.

Seriously I am building a tiny autopilot for aerial photography. The sensor is not that expensive if you look at it in EUR (this is Finnish product, there is mirror situation as with PICs: they are more expensive than ATMEGAs on this side of BIG WATER). The alternative is weighty: opamp, a few R+C, 18bit ADC and MPX sensor plus VREF and temp sensor.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Btw the time for servicing is only 25ms for 8Hz refresh rate.
Just divided the reading/writing routines into sub-ms chunks surrounded by cli()-sei(). Clearly butcher's solution but the jitter is acceptable, everything looks really stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Btw the time for servicing is only 25ms for 8Hz refresh rate.

Only if the temperature is critical, and you haven't mentioned that. In any case, that is still ms, nowhere near VERY SHORT in AVR terms to get a value.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But this is very short in terms of typical Windows context switching time. Bad habits.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But this is very short in terms of typical Windows context switching time.

:)

I've got a few apps that are based on the Analog Devices ADE7xxx energy meter chips. When doing current monitoring, it is important to measure the current at the same point in the AC cycle for stable readings. So the zero-crossing interrupt signal is used, similar to your DRDY. I'd call that SHORT, but still not VERY SHORT--the AC cycle is 15-20ms, and if the reading is held up for, say, one or two other ISRs to fire and there is 50-100us of jitter it is no big deal as the app averages readings between loop closing time anyway.

Now, I suppose one could construct an app where VERY SHORT is needed. Still possible as external interrupts are high on the priority list, and all ISRs are kept short. Interrupts could even be nested.

But surely not necessary in your slow, slow signal that can be bit-banged using us not ms.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

I'd call that SHORT, but still not VERY SHORT--the AC cycle is 15-20ms, and if the reading is held up

A whole period of the AC cycle takes about this long, but if you detect both the rising and falling zero crossing it occurs every 8-9ms.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

is there any code for reading from scp1000 with atmega128??
please help