![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Monk9514524 Guest
|
SPI communication problem |
Posted: Mon Dec 08, 2008 11:22 am |
|
|
I try to make my two 18F4620 communicate with each other.
One with 40MHz clock, the other with 10MHz.
Now, I make master setting with:
Code: | setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_16); | with 40Mhz clock
Slave setting:
Code: | setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16); |
I try to make it work for a while.
The master can make the right signal but some how the slave just receive the correct signal.
Please help. thanks for all.
Here is my code:
Code: | #include <18F4620.H>
#device ADC=10
#use delay (clock= 40000000)
#use rs232 (baud = 115200, xmit= PIN_C6, rcv= PIN_C7)
#define ccp2_period 1000
int8 duty_set=160;
#INT_CCP2 // Capture/Compare ISR
void system_clock_CCP2_ISR()
{
A4 = 1; // get a scope to see this
CCP_2 += ccp2_period;
spi_write(duty_set);
A4 = 0;
}
void main()
{
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_2 );
setup_ccp2 ( CCP_COMPARE_INT ); // configure CCP2 in COMPARE mode and ...
// CCP2 Interrupt on compare match
enable_interrupts ( INT_CCP2 );
enable_interrupts ( GLOBAL );
set_timer1(0);CCP_2=ccp2_period; // start the CCP2_ISR at 1 msec later
setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_16);
while ( 1 )
{
}
}
|
and slave code
Code: |
include <18F4620.H> // <18F452.H> // device header file from CCS-C
#device ADC=10 // choose 10 bit AD instead of 8
#use delay (clock= 10000000) // 20 MHz crystal oscillator
#use rs232 (baud = 28500, xmit= PIN_C6, rcv= PIN_C7, errors)
#define ccp2_period 250 // CCP2_compare_match_interrupt_period
int16 time_tick = 0; // system clock
int16 time_sec = 0;
//int datain=80;
//int16 ad_data;
#ifdef __PCM__ // PIC16Fxxx
#bit A4 = 0x05.4 // Port_A, pin #5, for CCS-C only
#bit TRISA4 = 0x85.4
#define PORTD *(int8 *)(0x08)
#define TRISD *(int8 *)(0x88)
#else // PIC18Fxxx
#bit A4 = 0xF80.4
#bit TRISA4 = 0xF92.4
#define PORTD *(int8 *)(0xF83)
#define TRISD *(int8 *)(0xF95)
#endif
/*
int16 interrupt_time=0, resolution=0,duty_length=0,duty_medium=0;
int16 duty_changer=0,duty_set=0,max_duty=0,min_duty,cycle=0,Duty_set_high=0;
*/
int16 interrupt_time,cycle;
int16 duty_length=0,duty_set=80,Duty_set_high=0;
#INT_CCP2 // Capture/Compare ISR
void system_clock_CCP2_ISR()
{
A4 = 1; // get a scope to see this signal
CCP_2 += ccp2_period; // setup critirion for next CCP2_ISR
// CCP_2 is defined in 16F877.H
if(spi_data_is_in())
{
duty_set=spi_read();
output_D(duty_set);
}
if ( cycle-- )
{
if (Duty_set_high<duty_set)
{
Duty_set_high++;
output_high(pin_B4);
//A4 = 0;
}
else
{
output_low(pin_B4);
//A4 = 0;
}
else {cycle=duty_length ; Duty_set_high=0 ;}
A4 = 0;
}
void main()
{
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_2 );
setup_ccp2 ( CCP_COMPARE_INT ); // configure CCP2 in COMPARE mode and ...
// CCP2 Interrupt on compare match
enable_interrupts ( INT_CCP2 );
enable_interrupts ( GLOBAL );
set_timer1(0);CCP_2=ccp2_period; // start the CCP2_ISR at 1 msec later
setup_adc_ports ( ANALOG_AN0 ); // RA0 as analog input
setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16);
set_tris_d(0);
output_d(0x0);
interrupt_time = ccp2_period * 2 /10;
duty_length = 16000 / interrupt_time ;
while ( 1 )
{
printf(" \r\n duty_set=%lu ", duty_set );
delay_ms ( 300 );
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 08, 2008 1:10 pm |
|
|
Quote: | setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16); |
Don't specify a clock divisor in the slave. The master supplies the clock.
On the slave, if you are not using \Slave Select, then you should add:
Quote: | #INT_CCP2
void system_clock_CCP2_ISR()
{
A4 = 1;
CCP_2 += ccp2_period;
if(spi_data_is_in())
{
duty_set=spi_read(); |
You are checking the SPI buffer in the CCP2 interrupt. Why ?
What if two bytes of SPI data arrive before an interrupt occurs ?
Normally, the SPI read operation is done in the #int_ssp interrupt.
That's the interrupt for the SPI module.
Quote: | setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_2 );
setup_ccp2 ( CCP_COMPARE_INT ); // configure CCP2 in COMPARE mode and ...
// CCP2 Interrupt on compare match
enable_interrupts ( INT_CCP2 );
enable_interrupts ( GLOBAL );
set_timer1(0);CCP_2=ccp2_period; // start the CCP2_ISR at 1 msec later
setup_adc_ports ( ANALOG_AN0 ); // RA0 as analog input
setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16);
set_tris_d(0);
output_d(0x0); |
Here, you are enabling global interrupts before you have finished doing
the setup code for all the modules. You should setup everything first,
and then enable interrupts. |
|
![](templates/subSilver/images/spacer.gif) |
Monk9514524 Guest
|
SPI c code problem~ |
Posted: Tue Dec 09, 2008 4:06 am |
|
|
Thanks PCM programmer
Because I need to produce 62.5Hz is about 16ms period,
the internal PWM module with 10Mhz clock can't produce that signal to reach 16ms.
I try to make the slave producing the PWM signal with the interrupt(system_clock_CCP2_ISR() ) counting.
My original thought make the function if(spi_data_is_in()) in every interrupt to know if the signal coming or not,
if that did then change the duty that slave make.
Code: |
if(spi_data_is_in())
{
duty_set=spi_read();
}
|
But somehow when I send the " duty_set = 160 " to slave, the number received with 64.
It seems there are something wrong with interrupt and spi function.
I already tried for period of time.
Master
Code: | setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16);
enable_interrupts ( GLOBAL );
|
Slave
Code: |
setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_CLK_DIV_16);
enable_interrupts ( GLOBAL );
|
And if I change the setting of slave to setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16|
SPI_SS_DISABLED);
It wouldn't receive anything even the master still produce the signal to slave.
1. I am curious about the code SPI_XMIT_L_TO_H meaning, is that necessary?
2. Because the master with 40Mhz clock and slave with 10Mhz clock, then should I make the slave setting changed from
SPI_CLK_DIV_16 to SPI_CLK_DIV_4?
BTW. I try to make two sensors receiving and calculate the math all in one interrupt, but the interrupt time became one unit of resolution of PWM signal, would decrease the PWM resolution.
Is there any way to make the PWM signal then, I don't need another PIC to produce PWM signal?
Thanks for all
Monk9514524 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Tue Dec 09, 2008 5:35 am |
|
|
You _must not have a clock speed selected in the slave at all_.
You need to understand the 'point' about synchronous communications. _Only_ the master device generates a clock. The slave clocks the data in, using the clock that is coming from the master. The speed of the slave processor, _does not have any effect at all_, except in that you may have to allow delays between bytes when the master sends, to allow the slave time to handle things. Selecting a 'clock' on the slave, gives you an impossible setup, that will probably stop everything working.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Monk9514524 Guest
|
SPI c code problem~ |
Posted: Wed Dec 10, 2008 2:26 am |
|
|
Thanks answering~Ttelmah
Because I need the Slave PIC to generate the 62.5Hz (16Ms) signal,and the inside PWM singal can not generate that long
period PWM, so I generate that signal with interrupt. Try to make SPI communcation in the interruption.
This time I changed the data receive in "while" loop in Slave setting.
Master(with 40Mhz) SPI setting in main function
Code: |
setup_spi(SPI_MASTER |SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16);
enable_interrupts ( GLOBAL );
|
Slave(10MHz) SPI setting in main function
Code: |
...
...
setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_CLK_DIV_16| SPI_SS_DISABLED);
enable_interrupts ( GLOBAL );
while ( 1 )
{
printf(" \r\n duty_set=%lu ", duty_set );
delay_ms ( 300 );
if(spi_data_is_in())
{
duty_set=spi_read();
//duty_set=1;
output_D(duty_set);
}
|
I made the Master transfer munber 170 to Slave, which binary code is 10101010.
then Slave received the signal, turn out to be 01010100.
It did receive the data but somehow it isn't right? |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Dec 10, 2008 3:08 am |
|
|
NO-CLOCK-SETUP-REQUIRED-FOR-A-SLAVE has already been said twice. Don't need to argue on it.
I wonder why you apparently don't use a slave select line. It's the usual, and to my opinion, only simple and robust method, to synchronize slave receiption. |
|
![](templates/subSilver/images/spacer.gif) |
Monk9514524 Guest
|
SPI c code problem~ |
Posted: Wed Dec 10, 2008 5:57 am |
|
|
FvM
I am sorry.
I just don't know how to do you told me to do?
Would you mean take away the setting in SPI_CLK_DIV_16
and find out how to use slave line?
Is it that ? |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Dec 10, 2008 6:38 am |
|
|
The settings SPI_SLAVE and SPI_CLK_DIV_16 are mutual exclusive in SPI hardware control register, a slave don't need and should not have a CLK_DIV_xx setting.
The other suggestion is to use a slave select as frame synchronisation signal, if possible. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|