|
|
View previous topic :: View next topic |
Author |
Message |
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
Problem with SPI slave |
Posted: Wed Apr 07, 2010 7:49 pm |
|
|
Hi,
I am getting rather frustrated as I cannot seem to see why my approach for what I am trying to do just does not work! I have two PIC's on separate boards; the first one is a master SPI (PIC18F2480) that gets data from an RS232 serial line, once it decodes the entry value for an address and a numeric value for a dac it sends this information via the SPI port to a second PIC (PIC16F88) that acts as a slave spi device, the second pic uses the hardware spi in slave mode and then uses a software I2C master mode to communicate to 5 separate dacs (MCP4725) the I2C seem to work perfectly and the spi data comming from the master spi pic also appear to be correct if one was to look at it on a logic analyzer that uses the spi logic protocol. In actuality; when I first wrote the code for both of these it appeared to work fine on the Proteus VSM simulation, however in the real world the slave spi does not seem to work.
My data to the slave is as follows: spi mode 1,1 3 bytes as shown below, the first byte is an address for the dac and the second and third byte form the 12 bit data for the dac.
Code: |
byte1(address) byte2(MSB) byte(LSB)
______ ______ _____ _______
|||||||| |||||||| ||||||||
|
sorry for the lousy text diagram above!
Looking at the data and timing everything looks correct on an SPI logic analyzer, but for some silly reason I cannot seem to get anything more than the first byte (address) received by the slave. I am sure that I am overlooking something or doing something stupid, but after staring at this for a long time, i can't seem to see the problem, perhaps someone else might see the real issue or have a better approach as to how to propperly receive these three bytes correctly. I have included most of my code for both devices, except for the header files. I am using V4.106 of the CCS compiler. Both PIC's are running on internal oscillator @ 8MHz, NWDT,NOMCLR.
Any help or hints would be greatly appreciated! (I believe the actual problem is in the slave code)
Code: | ////// Master SPI Code on a PIC18F2480 //////////////////////////////////////////////////////////////////////
#define SLAVECOMMAND 0x80
#define clrscr() puts( "\x1b[2J")
#define home() puts( "\x1b[H")
#define DACVFACTOR 0.0012
#define RVAL 82.5
#define RS232_BUFFER_SIZE 50 // allow for max number of chars
float volts,current;
int1 InBufferFlag = 0, CommandFlag = 0;
unsigned int8 channel;
unsigned int16 DacValue;
char rs232_buffer[RS232_BUFFER_SIZE];
char Function;
int8 rs232_nextin=0, rs232_nextout=0, rs232_lastin =0;
#int_RDA
void RDA_isr(void)
{char c;
c=getc();
rs232_buffer[rs232_nextin++] = c;
if(c == '\r')
InBufferFlag = 1;
if( (c == 'x') | (c == 'y') | (c == 'b')| (c == 'r'))
{ CommandFlag = 1; Function = c;}
if (rs232_nextin >= RS232_BUFFER_SIZE) {rs232_nextin=0;}
}
char bgetc(void)
{ char c;
while (rs232_nextout == rs232_nextin) {restart_wdt();}
c=rs232_buffer[rs232_nextout++];
if (rs232_nextout >= RS232_BUFFER_SIZE) {rs232_nextout=0;}
return(c);
}
void ClearBuff() // clear serial char buffer
{ unsigned int i;
disable_interrupts(INT_RDA);
rs232_nextin=0;
rs232_nextout=0;
InBufferFlag = 0;
CommandFlag = 0;
for(i=0; i< RS232_BUFFER_SIZE; i++)
rs232_buffer[i]=0;
restart_wdt();
enable_interrupts(INT_RDA); }
void Init()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
setup_spi(SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16); // mode 1,1 clock h when inactive data valid on clk lead edge
setup_wdt(WDT_OFF);
setup_wdt(WDT_ON);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_vref(FALSE);
output_high(PIN_B0);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
}
/************************* Routine I use to send to slave *****************************************************
void WriteToSlaveValue(unsigned int8 address, unsigned int16 data)
{ unsigned int8 data_in; // read dummy
unsigned int8 highbyte, lowbyte;
highbyte = data >>8;
lowbyte = data;
output_low(PIN_B0);
delay_us(10);
spi_write(address);
data_in = spi_read();
delay_ms(20);
spi_write(highbyte);
data_in = spi_read();
delay_ms(20);
spi_write(lowbyte);
data_in = spi_read();
delay_us(10);
output_high(PIN_B0);
}
/************************************************************************************************************
void main()
{
Init();
delay_ms(100);
clrscr();
home();
printf("Ready for command: \r\n");
while(1)
{
if(InBufferFlag || CommandFlag)
{
if(CommandFlag && Function == 'x'){ClearBuff(); WriteToSlaveCmd(Function);
printf(":%c\r\n",Function);}
if(CommandFlag && Function == 'r'){ClearBuff(); printf("Resetting PIC\r\n"); delay_ms(1000); reset_cpu();
}
if(InBufferFlag && rs232_buffer[0]== 'a')
{ rs232_buffer[0] <<= 8; //shift out the first byte char 'a' in this case
if(rs232_nextin > 0)
channel = bget_int8();
ClearBuff();
InBufferFlag = 0;
CommandFlag = 0;
//printf("DAC:%u = \r\n",channel);
}
if(InBufferFlag && rs232_buffer[0]== 'v')
{ rs232_buffer[0] <<= 8; //shift out the first byte char 'o' in this case
if(rs232_nextin > 0)
{DacValue = bget_int16();
WriteToSlaveValue(channel,DacValue);}
volts = DACVFACTOR * DacValue;
current = volts / RVAL;
current *= 1000;
printf("\r\nDAC:%u = %Lu Cts, Volts = %5.3g V, Iled = %5.1g Ma\r\n",channel,DacValue,volts,current);
ClearBuff();
InBufferFlag = 0;
CommandFlag = 0; }
}
restart_wdt();
}
} ///////////////////////////// end of master code ///////////////////////////////////////////////////
|
Code: |
////// Slave Code on a PIC16F88 //////////////////////////////////////////////////////////////////////
int8 SPIdataBuffer[3];
int1 DataCommandFlag = 0;
int1 FunctionFlag = 0;
int1 DacFlag = 0;
int1 SPIFlag =0;
#define COMMANDBYTE 0x80
#define BYTE1 0
#define BYTE2 1
#define BYTE3 2
#int_SSP
void SSP_isr(void)
{
SPIFlag =1; // not using this
}
void Init()
{ SET_TRIS_A(0b11110011);
SET_TRIS_B(0b11110011);
setup_adc(ADC_OFF);
// setup_spi(SPI_SLAVE|SPI_H_TO_L|SPI_CLK_DIV_16);
// ***the following lines set-up the SPI module did not trust CCS routines **
SSPEN = 1;
SSPM2 = 1;
SMP = 0;
CKE = 1;
CKP = 1;
BF = 0;
//***********************************
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
//enable_interrupts(INT_SSP);
// enable_interrupts(GLOBAL);
output_low(PIN_B3);
}
void main()
{
int8 DacAddress, ByteIndex =0;
unsigned int16 DacDataValue;
int8 i, DacMSB, DacLSB;
Init();
char cmd;
while(1)
{
/* while(!input(SPI_SS)) // tried this, same outcome always gets first byte but not the rest
{ if(BF)
{SPIdataBuffer[ByteIndex] = SSPBUF;
ByteIndex++; }
if(ByteIndex == 3)
{ DataCommandFlag = 1;
ByteIndex =0; }
} */
while(!input(SPI_SS)) // this does not do it either,always gets first byte but not the rest
{ if(spi_data_is_in())
{SPIdataBuffer[ByteIndex] = spi_read(0);
ByteIndex++;
SPIFlag =0;}
if(ByteIndex == 3)
{ DataCommandFlag = 1;
ByteIndex =0;}
}
if(DataCommandFlag)
{
if(SPIdataBuffer[BYTE1]== COMMANDBYTE) // if not a dac command
{ FunctionFlag = 1; cmd = SPIdataBuffer[BYTE3];} // it must be a function get the function
else
{ DacAddress = SPIdataBuffer[BYTE1]; // get the dac address
DacMSB = SPIdataBuffer[BYTE2]; // get the dac MSB value
DacLSB = SPIdataBuffer[BYTE3]; // get the dac LSB value
DacDataValue = make16(DacMSB,DacLSB); // reconstruct 12 bit value for dac
DacFlag =1;} // means the data is just for the dac
DataCommandFlag = 0;
}
if(FunctionFlag) {
switch (cmd)
{ case 'x':
output_high(PIN_B3);
break;
case 'y':
output_low(PIN_B3);
break;
}
FunctionFlag = 0;
}
if(DacFlag)
{ //WriteToDacOnly(DacAddress,DacDataValue);
WriteToDacAndEEprom(DacAddress,DacDataValue);
DacFlag = 0;
}
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu Apr 08, 2010 4:13 am |
|
|
Some comments though.
You are not sending mode 1,1.
Mode 1,1, requires:
SPI_H_TO_L | SPI_XMIT_L_TO_H
You are transmitting the data on the wrong edge, and currently running mode 1,0
Your receiver is also set for 1,0 though. Mode 1,1, requires CKP=1, CKE=0.
You can't clear the BF flag, by setting it to zero. You have to _read_ the data, which will clear the flag. This flag may well get set, when you first wake up. This is why it is marked in the data sheet as 'R', not 'R/W'.
On all flags like this, you must clear the condition, rather than just trying to change the flag.
Your initialisation, should use something like:
while(BF) spi_read();
to clear the BF flag.
Best Wishes |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Thu Apr 08, 2010 5:01 pm |
|
|
Thank you all,
I did have the incorrect SPI mode selected as indicated, but even after fixing that nothing seemed to work with the SPI slave, I finally got it working by increasing the time between bytes to ~650 us which I think is ridicuosly long, but apparently one thing that seemed to fix the SPI transmission of data was to get rid of the ; spi_read(0); after doing the spi_write(XXXX); on the master spi code? I am not too sure why that would have such an impact. |
|
|
|
|
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
|