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

SPI DI and External Interrupt by RB0
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JosedeJesusC



Joined: 29 Mar 2013
Posts: 24

View user's profile Send private message

SPI DI and External Interrupt by RB0
PostPosted: Wed Jul 31, 2013 7:57 pm     Reply with quote

Hi Everybody my question is:

the Data In PIN of SPI communication and the External Interruption can they both being work together in the same PIN RB0?
The device is PIC18F4550.

The trouble is the next:
I need to attend an external Interrupt by RB0 with the falling egde, then after a delay, by the same PIN, receive the serial data with SPI Communication as the code into the interrupt.

I tried via software change the PIN DI with the preprocessor function #SPI(DI = RB2) but that means I have to connect RB0 and RB2 with a wire. Doing this and looking at the oscilloscope the PIN SCLK RB1 don't do anything (so there's no synchronization with an external ADC)

Is there another external interrupt source which I can use or another option?

Thanks for your help
best regards!!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19254

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 12:15 am     Reply with quote

The SPI has it's own interrupt, which will trigger when a byte is received.
You can't remap the DI pin. Doing so means you are now using software SPI, so no SPI interrupt, and data can be missed. This is _only_ suitable for a master device, not a slave (which you seem to be talking about).
Yes, you can have the external interrupt enabled on the DI pin at the same time as the SPI is enabled, but it means nothing for SPI. Imagine the master sends you 0xFF?. The DI line will never drop..... It is the clock line that controls SPI, not the data line.

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 12:19 am     Reply with quote

I presume you are talking about a SPI master interface.

There's no problem in using the pin for both SPI DI and external interrupt function. You have to disable the
interrupt during SPI communication and clear the interrupt flag before reenabling it.

I'm doing the same with a CC1100 transceiver chip where the DI line signals state changes while the
SPI interface is idle.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 12:45 am     Reply with quote

His post is about a driver for the ads1254, for which this is his 5th thread.
JosedeJesusC



Joined: 29 Mar 2013
Posts: 24

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 8:14 am     Reply with quote

Thanks FVM and Ttelmah.

Yeah it's a Master.

The SPI behaivor is : when the data it's ready from the external ADC (as gently PCM programmer said it's ADS1254) the interrupt is executed.

The ADC notes with a falling edge so the data is ready when it's in low.

The data sheet says when the master's register which receive the data is full, then the interrupt is executed but not before isn't it?

I think the Telmah's idea it's good what do you think?

Thanks everybody by your time
I'm sorry if PCM Programmer is upset Embarassed It's not my purpose.
Ttelmah



Joined: 11 Mar 2010
Posts: 19254

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 8:35 am     Reply with quote

You are into a problem straight away. The ADS1254, is a 3.3v device. As such it will not produce enough voltage on a 'high' to directly drive the SPI of the 4550 at 5v. Far easier and better to switch to a PIC that uses 3.3v as well, like the 26J50. If you run the 4550 at 3.3v, you need the LF version, and are limited to 18.7MHz maximum. Look carefully at the data sheet. Problem is that the sheet is for both chip versions, so you get people thinking the 4550, can run down to 2v. It can't.
To run the PIC at 5v, with SPI, you need hardware buffering on the DI line.

With a suitable PIC, what you are talking about can easily be done.
You just enable the external interrupt, set it up for high to low trigger, and interrupt when the line drops. Then you don't need to do anything in the handler, except the the SPI transaction. The interrupt is cleared when the routine exits, so the 'extra' triggers won't matter. A few things depend on what your clock rate is to the ADC. - how long after the data line drops you have to wait before data can be clocked in particular.

Best Wishes
JosedeJesusC



Joined: 29 Mar 2013
Posts: 24

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 10:25 am     Reply with quote

Hi Ttelmah !!!!
thanks for your reply, I think your way to do it is better. I'm going to use the 26j50, low consumption, high speed, it's great!!.

Yeah the ADS1254 has its own clock source with crystal interfaced with CMOS hex inverters, and frequency divider with D flip-flop, to ensure the frequency rejection, data rate and another features. Thanks so much.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 1:28 pm     Reply with quote

Quote:
the ADS1254 has its own clock source with crystal interfaced with CMOS hex inverters

What frequency are you putting on the CLK pin of the ADS1254 with
your external crystal circuit ? Is it 8 MHz ? That's the maximum.

The 18F26J50 can run up to 48 MHz, with either external or the internal
oscillator. What frequency will you use for the PIC oscillator ?

This frequency ratio (PIC oscillator to ads1254 CLK) is important because
it determines if it's even possible to read out the 24 bits of data in the
alloted time slot. The ads1254 has a time slot where you must read
out the data within that time. If you're using hardware SPI, then it's not
really a problem. Hardware SPI can run with a fast SCLK.

But if you're using software SPI on pin B0 (combining the detection of
DRDY and the reading of data on the same pin), then you have to carefully
make sure that your software SPI read routine is fast enough.

So that's why I'm asking what is the CLK frequency on the ads1254, and
what is the oscillator frequency of the PIC.
JosedeJesusC



Joined: 29 Mar 2013
Posts: 24

View user's profile Send private message

PostPosted: Sun Aug 11, 2013 11:36 pm     Reply with quote

Hi PCM programmer Smile !!!!

Thanks for your reply.
The pic use a 4MHz crystal for the USB module, and derive the 48 MHz.

Ok! I'm going to use the counter CD4040 to divide the max Frequency (8 MHz of the crystal interfacing with cd4013bp) because I'd like to have the frequencies available to setup the ADS1254, but I spend to have 60 Hz as a maximum frequency of the signal which comes from load cell in this particular application.

I've read the data sheet of the ADC and my target is after the falling edge(here it comes in the external interrupt by RB0) wait 12 CLK cycles and then receive the data with the SPI function in the same pin, as you said the clock of the 18F26J50 is 48 MHz so the SPI may be SCLK = 48MHz/16, as you know I can do it with 48MHz/4, that frequency will be the final until I can see in LabVIEW the response, but I now want to see the behavior with the oscilloscope. Step by step.
I can see the falling edge of the ADC with exactly 6 CLK cycles of duration in the oscilloscope (with 5 volts :S in the digital side), so with another 6 cycles the data out function begins (here comes in the SPI function), the CLK is just 5 KHz to receive signal with around 12 or 13 Hz.

I think with 12MHz as SPI's SCLK is enough to receive the data in the final board in the case of 8 MHz as ADC's CLK.

What do you think? isn't it right?

best regards
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Aug 12, 2013 4:12 pm     Reply with quote

Quote:

I think with 12MHz as SPI's SCLK is enough to receive the data in the final
board in the case of 8 MHz as ADC's CLK.

Yes, a 12 MHz instruction cycle frequency (PIC running at 48 MHz) is fast
enough to read the 24 bits using software SPI. But you have to be
careful with the read loop, and make sure it's fast enough. I have done
that in the program shown below.

Here is a sample driver for the ADS1251. I haven't completely tested it,
but it appears to work OK. Note that this code is for the ADS1251, which
is a single-channel A/D chip. It doesn't have any channel select pins.
So it could be modified for the ads1253 or ads1254 by adding lines of
code to select the channel, and also add the required delay time after
changing the channel. It could also work for the signal channel ads1252.
However, I have only tested this program with the ads1251.

Inside the unrolled loop, SCLK high time is only 166 ns. SCLK high time
is not specified in the ads1251 data sheet. But I don't think it's a problem
because SCLK is specified to run at 8 MHz max. In that case, the high
time would be only 62.5 ns. So I think we're OK running it at 166 ns.

Note that this driver does not use an interrupt routine. Instead, it polls
the hardware External interrupt flag in a for() loop.
Code:

#include <18F4550.h>
#fuses HSPLL,NOWDT,NOLVP,PLL5,CPUDIV1,NOPBADEN
#use delay(clock=48M)
#use rs232(baud=9600, UART1, ERRORS)

#define ADS1251_DOUT_DRDY_PIN  PIN_B0 
#define ADS1251_SCLK_PIN       PIN_B1

//-------------------------------------------
#define ADS_CLK_FREQ  8000000
#define ADS_SAMPLE_FREQ  (ADS_CLK_FREQ / (6 * 64))  // A/D samples/second

#define ADS_CONVERSION_CYCLE_PERIOD_IN_USEC  ((384 * 1000000) / ADS_CLK_FREQ)

#define ADS_TIMEOUT_IN_USEC  ADS_CONVERSION_CYCLE_PERIOD_IN_USEC

//------------------------------------------------------
// Utility macros

#define BytePtr(var, offset)   (&(char)var + offset)

#ifdef __PCM__
#define interrupt_enabled(x)  !!(*make8(x,1) & make8(x,0))
#endif
#ifdef __PCH__
#define interrupt_enabled(x)  !!(*(make8(x,1) | 0xF00) & make8(x,0))
#endif

#ifdef __PCB__
#error  interrupt_enabled(x) is not supported for the PCB compiler.
#endif
#ifdef __PCD__
#error  interrupt_enabled(x) is not supported for the PCD compiler.
#endif

//---------------------------------------------
// This routine returns TRUE if we successfully read a 24-bit signed
// integer result from the ads1251.  If the ads1251 didn't output a
// \DRDY pulse within the expected time, then it returns FALSE.
// The A/D result is not valid in that case.  If the result is valid,
// it is returned in the reference parameter. See the code in main()
// which shows how to call the function.       

int8 read_ads1251(signed int32 &result)
{
int8 i;
int8 gie_enabled;

// We can't allow random delays to be inserted into this routine
// by any interrupts that are running (in a larger program). 
// If Global interrupts are enabled, then disable them now.
if(interrupt_enabled(GLOBAL))
  {
   disable_interrupts(GLOBAL);
   gie_enabled = TRUE;   // Note that interrupts were enabled
  }
else
  {
   gie_enabled = FALSE;
  }

ext_int_edge(H_TO_L);  // Interrupt on falling edge of \DRDY pulse
clear_interrupt(INT_EXT);

// The duration of the timeout loop is not critical.
// It just needs to be a little longer than the conversion cycle.
// Therefore, we can set it to the length of the conversion cycle
// in usec (by using one call to delay_us(1) per loop), and the
// additional loop overhead loop overhead execution time doesn't matter.

// Wait for a negative edge on the \DRDY pulse.
for(i = 0; i < ADS_TIMEOUT_IN_USEC; i++)   // 8 ins. cycles/loop
   {
    if(interrupt_active(INT_EXT))
       break;
    delay_us(1);
   }

if(i == ADS_TIMEOUT_IN_USEC)
   return(FALSE);

delay_us(2);  // Wait at least 1.5 usec from \DRDY falling edge

// Then read 24 bits of data from the ads1251.
// This partially unrolled loop takes 29.41 usec at 48 MHz.
// This is easily within the DOUT period of 43.5 usec.
for(i = 0; i < 6; i++)
   {   
    output_low(ADS1251_SCLK_PIN);
    shift_left(&result, 3, input(ADS1251_DOUT_DRDY_PIN));
    output_high(ADS1251_SCLK_PIN);

    output_low(ADS1251_SCLK_PIN);
    shift_left(&result, 3, input(ADS1251_DOUT_DRDY_PIN));
    output_high(ADS1251_SCLK_PIN);

    output_low(ADS1251_SCLK_PIN);
    shift_left(&result, 3, input(ADS1251_DOUT_DRDY_PIN));
    output_high(ADS1251_SCLK_PIN);

    output_low(ADS1251_SCLK_PIN);
    shift_left(&result, 3, input(ADS1251_DOUT_DRDY_PIN));
    output_high(ADS1251_SCLK_PIN);
 }

output_low(ADS1251_SCLK_PIN);

// If Global interrupts were enabled, we can re-enable them now.
if(gie_enabled)
  {
   enable_interrupts(GLOBAL);
  }

// Do the sign extension to 32 bits.
if(bit_test(result, 23))
   *BytePtr(result, 3) = 0xFF;
else
   *BytePtr(result, 3) = 0x00;

return(TRUE);
}

//=======================================
void main()
{
signed int32 adc_value;
int8 status;

output_low(ADS1251_SCLK_PIN);  // Initialize SCLK to idle state

delay_ms(100);  // Wait for PIC's PLL oscillator to stabilize

printf("Start\n\r");


while(1)
  {
   status = read_ads1251(adc_value);

   if(status == TRUE)
      printf("%lx \n\r", adc_value);
   else
      printf("Timed out \n\r");

   delay_ms(1000);
  }

}



There is one issue with the DOUT/DRDY interface with these chips.
The MSB of the 24-bit result is seen on the DOUT pin during the DOUT
period, before you start sending SCLK pulses to read the data. This is
stated in the ads125x data sheets. Since the top bit is the sign bit, if the
input voltage is positive, the sign bit will be 0. This means that the \DRDY
pulse could be aliased by the DOUT level. See the diagram below:
Code:

     |  1.5us  |
     |         |
       
      \DRDY                   DOUT
      pulse                  period
______    ______                                       _______
     |____|    |_______________________________________|
               
     ^         ^
     |         |
   \DRDY      DOUT for positive sign bit
   falling    aliases the falling edge of
   edge       the DRDY pulse              Note:  \DRDY pulse is 750 ns

It's possible that the falling edge of the start of DOUT could be
falsely interpreted as the falling edge of \DRDY. This could happen
if the code happens to clear the INT_EXT interrupt flag just after
the \DRDY falling edge. In 1.5 usec, it will see the falling edge
of the beginning of the DOUT period. The code will detect and
interpret the DOUT falling edge as the start of a read cycle.
But it doesn't matter. That's because the code that reads 24 bits
of data during the DOUT period is fast enough to finish reading
well before the end of the DOUT period. If a small part of the
DOUT period passes before we start reading, there is still plenty
of time left to read all the data.

This discussion is based on an 8 MHz CLK signal for the ads1251
and a PIC running at 48 MHz.

Also, the DOUT period is shown as a constant low level in the diagram.
In fact, when you start issuing SCLK pulses to read the data (after
the falling edge of DOUT), the DOUT signal will become 1's and 0's,
depending on the data from the ads1251. Only the first part of DOUT
will be a low level, if the sign bit is positive.
JosedeJesusC



Joined: 29 Mar 2013
Posts: 24

View user's profile Send private message

PostPosted: Fri Sep 13, 2013 9:03 pm     Reply with quote

Hi PCM programmer !!!

I'm sorry by the late Embarassed I haven't seen your reply till now !!!! The microcontroller 18F26J50 arrived from USA !!! this morning since I ordered it 1 month ago because it was in stock.

Looking at the code OMG!!!! you have taught me a different way to handle interrupts, I never thought in use the EXT INT as a flag to beginning the data transfer, but I've got a doubt. What is the function of the utility macros?

and does the CCS Compiler have the same USB support of this microcontroller?
I've seen into the forum some code examples but the user don't be so sure if the USB is HI or BULK transfer.

Thanks so much for your valuable code, the ADS1251 is close in behavior with the ADS1254, the only difference are the SEL-CH bit but easily the code can be adapted.

Best regards !!!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Sep 13, 2013 9:49 pm     Reply with quote

The BytePtr macro allows you to insert a byte into a 16 or 32 bit variable.
I use it to do sign-extension. This is shown in the code.

The interrupt_enabled() macro allows you to check if global interrupts
have been enabled in some other part of the program. If it's enabled,
then it is temporarily disabled while 24 bits of data are read from the
ads1251. The ads1251 read operation has to be done in a specified short
amount of time. Interrupts can not be allowed during the read operation
because they would delay the completion of read loop. It must finish quickly.

I don't know anything about USB with this PIC.
Ttelmah



Joined: 11 Mar 2010
Posts: 19254

View user's profile Send private message

PostPosted: Sat Sep 14, 2013 2:24 am     Reply with quote

On the USB, depends on the age of your compiler.

At the top of pic18_usb.h, it lists the chip families supported.

The 26J50, was added around the late 4.0xx versions. Wasn't there in the 4.07x area, but was by the 4.09x area.

They are nice chips, with lots of extras, and enough ROM/RAM to do a lot of things. Seem to have fewer 'bugs' than many others.

Best Wishes
JosedeJesusC



Joined: 29 Mar 2013
Posts: 24

View user's profile Send private message

PostPosted: Wed Oct 02, 2013 1:37 pm     Reply with quote

Hi everybody I've got a trouble, the pic18f26j50 doesn't do anything in the part of the for loop (in the code above), when the interrupt_active(EXT_INT), is executed, the program is stagnated, why?, I've tried with the register INTCON, INTCON2 and RCON to config the interrupt by pin B0, in low priority (compatibility mode with 16Fxx familiy) but nothing.

Best regards
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Oct 02, 2013 2:03 pm     Reply with quote

Quote:
I've tried with the register INTCON, INTCON2 and RCON to config the interrupt

Post your code.

What is your compiler version ?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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