CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Simultaneous Access of FRAM Problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

Simultaneous Access of FRAM Problem
PostPosted: Mon Apr 02, 2007 12:47 pm     Reply with quote

3.236 18F6627

Hello All,

I'm reading and storing an ADC value in FRAM in an INT_AD ISR. The conversion is started using the special event feature of the ECCP2 as suggested by Ttelmah.

My problem is this, I need to be able to pull data from the FRAM for processing in a large chunk (1024bytes). I was having problems and finally figured out that the ISR was interrupting the transfer of the data... duhhh.

I guess I need to write a routine to deal with all the issues that this raises. Is there an example to help me or a term to search for that might get me started?

My first approach would be to abandon the sequential read from FRAM. That obviously won't work because of the time involved and the need for the ISR to store values every ~4mS. I could use a while loop and a single value FRAM read routine. I'd have to disable the INT_AD prior to the read and re-enable just after. I'm wondering how bad that would bugger up my timing in reading the signal from the ADC...

Any ideas or suggestions would be greatly appreciated,

John
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Mon Apr 02, 2007 1:27 pm     Reply with quote

I don't know if this approach will be sufficient for your needs....

If there is a flag/bit you can test for, then this becomes quite easy. What you need to know is if the A/D conversion has been initiated. I know that the A/D's GO/DONE bit in the ADCON register will indicate this, but if this bit is only set for a very short period of time it's likely that you'll miss the event entirely.

My thinking goes like this. The FRAM read routine will be of the form

Code:
while (!done || !busy) {
   // do reads here
   if (busy) { // this bit is set by the ECCP2 - it signifies that an A/D
      // conversion is now in progress, so you should save what address
      // you're now at, and terminate the read so that you can exit the
      // FRAM read 'cleanly'
   }
   // you also have a test to see if you've read all 1024 bytes - if so
   // done is now true to exit from the while loop
}


When the A/D conversion is internally triggered, if a read is in progress, then this type of code structure should pick that up and kick itself out of the read, hopefully before the RA interrupt gets triggered. When the RA interrupt is finished executing, the while loop should be automatically re-entered because 'done' isn't true yet. Just ensure that the first time through the loop the code calls a read from 'address' - which was either set to 0 or was set to whereever the routine left off.

If the GO/DONE bit is set for a relatively long time - say it stays set until the processor actually completes an A/D conversion, then this approach will probably work.
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

View user's profile Send private message Visit poster's website

PostPosted: Mon Apr 02, 2007 1:36 pm     Reply with quote

..edited..
my post is not applicable as this is SPI and
not I2C..
see below


Last edited by treitmey on Tue Apr 03, 2007 2:40 pm; edited 3 times in total
sjbaxter



Joined: 26 Jan 2006
Posts: 141
Location: Cheshire, UK

View user's profile Send private message Visit poster's website

PostPosted: Mon Apr 02, 2007 2:03 pm     Reply with quote

I don't suppose you wired up the HOLD pin of the FRAM to an I/O pin on the pic.

If you did, you could put the FRAM in HOLD in the INT_AD and release it at the end of the interrupt routine. Theoretically, as the ISR kicks in, the FRAM read function gets halted (as the context is switched to the ISR), the FRAM current operation gets suspended and when the ISR is complete, the FRAM is released and the context switches back to the point in the read function where it was before. That's what the HOLD pin is designed for.

If you haven't wired the HOLD pin .... ignore all the above !! ;-)

It doesn't help for writing the value of the AD you have just read, but it does deal with how to handle the interruption a large read (or write) operation.
_________________
Regards,
Simon.
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Mon Apr 02, 2007 3:14 pm     Reply with quote

Guys,

Thanks for the fantastic ideas. I'll digest them this evening when I have a chance. A couple of notes in the mean time...

Sorry I forgot to include it: FM25256 SPI chip.

Newguy... I think I'll end up with your approach.

Treitmey... Good idea, but not sure if I want to move control of AD reads back and forth between the interrupt and the fram_read function. I'll look at it more deeply.

Simon... I didn't implement it, BUT I have several pins left over and could possibly do it. I need to do some more reading and see if it will work.

Thanks again,

John
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Mon Apr 02, 2007 6:45 pm     Reply with quote

Here is my first go at it. I can't test it yet, but I thought I'd share it and see if anyone has any thoughts on my approach.

Code:
      //continue until all the data is transferred to the holding array
      while(holding_array_index < N)
      {
         //if not currently making an AD conversion
         //and there's enough time left to read another value
         if(!GO_DONE && (get_timer3() < 20000))
         {
            //read the value from FRAM
            holding_array[holding_array_index] = read_int16_fram(starting_fram_addr);
            //increment to the next holding array location
            holding_array_index++;
            //increment to the next FRAM location
            starting_fram_addr += 2;
         }     
      }


I couldn't think of any other way to track whether another conversion was coming up. The TIMER_3 value is 39025, so I start with about 1/2 duty cycle for reading from FRAM. I was going to tweak it up until I had problems and then reduce it a little. Not very scientific, but I don't know how to calculate the overhead to make it as precise as possible.

Simon,

It's looking like your approach makes the most sense. I think I'm going to try the previous approach and get it working, then I'll try yours.

EDIT: Doesn't look like that will work after doing some reading.

Thanks again,

John
Ttelmah
Guest







PostPosted: Tue Apr 03, 2007 2:17 am     Reply with quote

I'd suggest sybchronising the 'read' operation to the interrupt.
Have a global 'bit' field. Call it something like 'clear_to_go'.

Then in the interrupt, have a line like:
Code:

clear_to_go=true;

Then in the routine to read the data block, have:
Code:


clear_to_go=false;
while(!clear_to_go) ;
//When you get here, an int_ad, will have _just_ happened, and there
//should be time to read a block


I use this approach, to synchronise a 'main' operation, to a PWM, for similar reasons.

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Tue Apr 03, 2007 8:03 am     Reply with quote

RJ,

I think I see what you are doing, but I still have a couple of questions.

For your approach to work, I assume that the data block needs to be a fixed and known size... obviously small enough to be read between interrupts.? How would you determine how large of a block to read? I'm going to test it with a couple get_timer3()'s on each side and see how long a single read takes, and then do the math and add some padding....

Was the ! a typo in your example? Wouldn't it be:
Code:
int_ad
clear_to_go = TRUE;

data_transfer()
{
   while(data_needs_to_be_transferred)
   {
      clear_to_go = FALSE;
      while(clear_to_go)
      {
         read_a_fixed_size_block_here
         break;
      }
   }
}


Thanks,

John

EDIT:

I see that my 'while' won't work. I think I see how yours works, now.... duhh.
Ttelmah
Guest







PostPosted: Tue Apr 03, 2007 9:11 am     Reply with quote

FRAM reads, should be pretty fast. Normally limited by the clock speed of the interface, and how long it takes to transfer 8 bits. Now if (for instance), you are using a normal I2C unit, at 400Hz, then you only send the initialisation once, and the reads can be performed sequentially. I'd have expected to be able to move perhaps 20000+ bytes/second (including the overheads in accessing a target array etc.). So 1024 bytes, should only need perhaps 1/20th second. If this is too long, then instead transfer a smaller block, and do repeated transfers the same way.
Glad you worked out my 'logic'... Smile

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Tue Apr 03, 2007 9:25 am     Reply with quote

Using part at 40MHz, SPI FRAM at clock_div4.

Running the timer tests now and see that I can get about 512 bytes transferred between the interrupts in sequential transfer. Interrupts are every 1/256 of a second.

Looks like it will work great after I finish swapping everything over to your method.

Thanks a bunch,

John
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group