|
|
View previous topic :: View next topic |
Author |
Message |
GregPIC Guest
|
SPI Communication Problems |
Posted: Wed Jun 07, 2006 9:49 am |
|
|
I'm having trouble with SPI communications between two uC's. The basic setup is like this:
[PC]<--(RS232)---->[Max232]<-->[PIC18F8390]<---(SPI)--->[PIC16F88]
I have verified that I can send the data over RS232, and it will be output over SPI (as seen with a scope) at the PIC18F8390. The 18F doesn't seem to see any data but junk.
The data received by the 16F is converted into two 12-bit numbers to send to a pair of DAC's. The DAC's never update. The data is then sent back to the 16F and back to the PC for verification. I cannot get the data to transfer back either, but this may make sense if the 16F can't read in the data in the 1st place.
18F Code.h
Code: |
#include <18F8390.h>
#device adc=10
#FUSES WDT //Watch Dog Timer uses 1:32 Postscale
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES BORV28 //Brownout reset at 2.8V
#FUSES NOPUT //No Power Up Timer
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOMCLR //Master Clear pin enabled
#FUSES LPT1OSC //Timer1 configured for low-power operation
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#use delay(clock=4000000, RESTART_WDT)
#use rs232(baud=9600,xmit=PIN_C7,rcv=PIN_C6, RESTART_WDT)
#byte TMR0 = 0x01
#define PORTA_TRIS 0b11111111 // All Inputs - Not Used
#define PORTB_TRIS 0b11111110 // All Inputs except RB0, used for SS
#define PORTC_TRIS 0b11010111 // SDO RC5, SDI RC4, SCK RC3
#byte SSPBUF = 0x0FC9
#bit SSP_BF = 0x0FC7.0
//*************************************************************************************************************************
//-----------------------------------------------------------------------------------
// Variables for the RS232-Connection //
int RS232_Rx[12]; // Inputbyte
int RS232_Tx[12]; // Outputbytes
int RS232_TxCount; // Counter for Outputbytes
int RS232_POINTER;
short RS232_Receive_Complete;
short RS232_Receive_Successful;
#define RS232_IN_START 0xA7 // RS232 Receive Start Signal
#define RS232_IN_STOP 0x7A // RS232 Receive Stop Signal
#define RS232_OUT_START 0xA9 // RS232 Transmit Start Signal
#define RS232_OUT_STOP 0x9A // RS232 Transmit Stop Signal
//-----------------------------------------------------------------------------------
// Variables for SPI //
int SPI_IN_CHO;
int SPI_IN_CH1;
int SPI_OUT_CH0;
int SPI_OUT_CH1;
#define SPI_OUT_STOP
#define SPI_IN_STOP
#define SPI_OUT_START
#define SPI_IN_START
//-----------------------------------------------------------------------------------
void ConfigureIO();
void PreLaunch();
void Launch();
void Clear_RS232_INPUT();
void Timer();
void Send_RS232(int Tx_Byte);
void SPI_TxRx();
//------------------------------------------------------------------------------------
// Communications Protocol
//
// PC Send / uC Receive
// Bytes: Start CH0_H CH0_M CH0_L CH1_H CH1_M CH1_L STOP
// 0xAF 0x1# 0x2# 0x3# 0x4# 0x5# 0x6# 0xFA
//
// PC Receive / uC Send
// Bytes: Start CH0_H CH0_M CH0_L CH1_H CH1_M CH1_L STOP
// 0xAA 0x1# 0x2# 0x3# 0x4# 0x5# 0x6# 0xFF
//
// Each D/A is 12 bits. MSB _ _ _ _ | _ _ _ _ | _ _ _ _ LSB
// H M L
// The 12 bits are divided into nibbles (shown as a # above)
//-----------------------------------------------------------------------------------
|
18F Code.c
Code: |
#include "18F Code.h"
void PreLaunch(){
setup_oscillator(OSC_4MHZ|OSC_NORMAL); // External XTAL 4MHz
//setup_wdt(WDT_ON);
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);//T1_INTERNAL
setup_timer_2(T2_DIV_BY_16,125,1); //4e6/4/2/16/125 = 250Hz
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_counters(RTCC_INTERNAL,RTCC_DIV_2); // Timer0 for RTCC
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_T2 | SPI_XMIT_L_TO_H);
setup_low_volt_detect(FALSE);
setup_lcd(LCD_DISABLED);
SSPBUF = 0;
ConfigureIO();
RS232_Receive_Successful = False;
Clear_RS232_INPUT();
RS232_POINTER=0;
}
void ConfigureIO() {
Set_TRIS_A(PORTA_TRIS);
Set_TRIS_B(PORTB_TRIS);
Port_B_Pullups(True);
Set_TRIS_C(PORTC_TRIS);
output_high(PIN_B0);
}
void Clear_RS232_INPUT() {
int i;
for (i = 0; i < 8; i++) {
RS232_Rx[i]=0;
}
RS232_POINTER=0;
}
void SPI_TxRx() { // Send/Receive SPI
int i;
output_low(PIN_B0); // CS to other uC
delay_ms(20);
for (i=0; i < 8; i++) { // Transmit SPI Data
spi_write(RS232_Rx[i]);
delay_us(200);
}
delay_ms(40);
for (i=0; i < 8; i++) { // Receive SPI Data
RS232_Tx[i] = spi_read(0);
delay_us(200);
}
delay_ms(20);
output_high(PIN_B0); // CS to other uC
delay_ms(20);
for (i=0; i < 8; i++) { // Transmit RS232 Data
putc(RS232_Tx[i]);
delay_us(20);
}
}
void main() {
PreLaunch();
while(1) {
restart_WDT(); // Reset Watchdog
// Wait for RS232 Data Input
// RS232_Receive_Successful ... Flag set when all data is in, stop confirmed
RS232_Receive_Successful=False;
RS232_Rx[RS232_POINTER] = getc(); // Read-Out received byte
if (RS232_Rx[RS232_POINTER] != ' ') { // Determine if data is received??? Better way?
if (RS232_Rx[RS232_POINTER] == RS232_IN_START) {// Reset RS232 Pointer at
RS232_Rx[0] = RS232_Rx[RS232_POINTER];
RS232_POINTER = 1;
RS232_Receive_Successful = False;
} else if (RS232_Rx[RS232_POINTER] == RS232_IN_STOP) {
if (RS232_POINTER == 7) {
RS232_Receive_Successful = True; // Stop bit confirmed, data complete
} else {
RS232_Receive_Successful = False; // Stop bit received, data missing
Clear_RS232_INPUT();
}
} else {
if ((RS232_POINTER == 7) && (RS232_Rx[RS232_POINTER] != RS232_IN_STOP)) { //
Clear_RS232_INPUT();
RS232_POINTER=0;
} else {
RS232_POINTER++;
}
}
}
delay_ms(100);
if (RS232_Receive_Successful==True) {
// Output SPI Data, Input SPI Data (to verify) and Output RS232_OUT
SPI_TxRx();
Clear_RS232_INPUT();
RS232_Receive_Successful = False;
}
}
}
|
16F Code.h
Code: |
#include <16F88.H>
#device adc=10
#include <STDLIB.h>
#fuses INTRC, NOWDT, PUT, NOPROTECT, BROWNOUT, NOLVP, MCLR, NOCPD, NOWRT, NODEBUG, FCMEN, NOIESO
#use delay(clock=2000000)
#use fast_io(A)
#use fast_io(B)
#define DAC_COMMAND 0x70 // 0111 (DAC_A | BUFFERED | GAIN_1 | OUTPUT_ENABLED)
#define PORTA_TRIS 0xFF // All inputs (for ADC).
#define PORTB_TRIS 0xF2 // 11100010 was 00011101 1D
#define PORTB_DEFAULT 0x09 // 00000000
// PIN_B1 is unused in this model
// PIN_B2 is used for serial data input
// PIN_B2 is used for serial data output
// PIN_B5 is uC serial transmit
// PIN_B6 is ICSP Clock and //Switch A Input
// PIN_B7 is ICSP Data and //Switch B Input
#define DAC_SELECT_0 PIN_B0
#define DAC_SELECT_1 PIN_B3
#define DAC_DATA_IN PIN_B2
#define DAC_CLK PIN_B4
// These are the exclusive modes of operation.
#define MODE_STARTUP 0x01 // 0000 0001 Set in PreLaunch
#define MODE_NORMAL 0x02 // 0000 0010 Set in Launch
// State variables.
int ModeG; // Tracks current progam state (MODE_*).
unsigned int uiConfig;
#define Offset 16
#define Slope 16
#ifndef NO_AVG
#define AVG0 0.8
#define AVG1 0.2
#else
#define AVG0 0
#define AVG1 1
#endif
/* Function Prototypes */
void PreLaunch();
void ConfigureIO();
void Launch();
void SetOutputs();
void WriteDAC(long int value, int1 chan);
|
Code: |
[b]16F Code.c[/b]
void main() {
int abc;
int i;
unsigned long int abcd;
int data[8];
short DataCompleteFlag;
PreLaunch(); // Configures interal regs., sets DAC output to 0x0000
Launch();
delay_ms(50);
for (abc = 0; abc < 8; abc++) {
data[abc] = 0;
DataCompleteFlag = True;
}
while (1) {
DataCompleteFlag = False;
if ( !input(pin_B5) ); // Wait for CS low
// Receive Data
while ( !spi_data_is_in() ) { // Wait for Data
}
for (abc = 0; abc < 8; abc++) {
data[abc] = spi_read();
DataCompleteFlag = True;
}
data[0] = 0xA9; // Change start/end bytes
data[7] = 0x9A;
for (abc=0; abc < 8; abc++) {
spi_write(data[abc]);
}
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_T2 | SPI_XMIT_L_TO_H); // Set SPI to write to DAC's
delay_ms(250);
abcd = (data[1] & 0x0F) * 256 + (data[2] & 0x0F) * 16 + (data[3] & 0x0F);
WriteDAC(abcd, 0);
delay_ms(200);
abcd = (data[4] & 0x0F) * 256 + (data[5] & 0x0F) * 16 + (data[6] & 0x0F);
WriteDAC(2000, 1);
delay_ms(20);
// Set SPI back to read from RS232
setup_spi(SPI_slave | SPI_SS_DISABLED | SPI_L_TO_H | SPI_XMIT_L_TO_H);
delay_ms(250);
}
}
void PreLaunch() {
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_16,125,1); //2e6/4/2/16/125 = 125Hz
ModeG = MODE_STARTUP;
ConfigureIO();
setup_wdt(WDT_576MS);
}
void Launch() {
restart_wdt();
delay_us(ADC_DELAY);
}
void ConfigureIO() {
set_tris_a(PORTA_TRIS);
setup_adc_ports(sAN0|sAN1|sAN2|sAN3|sAN4|VSS_VREF);
setup_adc(ADC_CLOCK_INTERNAL);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
port_b_pullups(TRUE);
set_tris_b(PORTB_TRIS);
output_b(PORTB_DEFAULT);
setup_spi(SPI_SLAVE | SPI_SS_DISABLED | SPI_L_TO_H | SPI_XMIT_L_TO_H);
}
void WriteDAC(unsigned long int value, int1 chan) { // This function works properly
unsigned int CmdHigh, CmdLow;
CmdHigh = (DAC_COMMAND & 0xF0) | ((value & 0x0F00) >> 8);
CmdLow = value & 0xFF;
if (chan == 0) {
output_low(DAC_SELECT_0);
spi_write(CmdHigh);
spi_write(CmdLow);
output_high(DAC_SELECT_0);
} else if ((uiConfig & CONFIG_TEMP_LOOP) && (chan == 1)) {
output_low(DAC_SELECT_1);
spi_write(CmdHigh);
spi_write(CmdLow);
output_high(DAC_SELECT_1);
}
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Wed Jun 07, 2006 10:17 am |
|
|
Obvious thing is that both chips cannot be 'master'...
The 'master' chip, is the one that generates clock pulses for the transaction. You have both chips set to do this.
Best Wishes |
|
|
GregPIC Guest
|
|
Posted: Wed Jun 07, 2006 12:53 pm |
|
|
Maybe this will not work how I wanted it to, but I wanted the 18F to be the master for comm. to the 16F.
The 16F device must be the master to communicate to the DAC's, so after it receives and responds with data, it switches to Master to talk to the DAC's. After that is complete, it switches back to be the slave. |
|
|
Ttelmah Guest
|
|
Posted: Wed Jun 07, 2006 2:25 pm |
|
|
SPI, sends data in both directions at once, clocked by one 'master' chip. Just have the chip that is sending/asking for the data as master, and the other as slave. If you want to turn the bus 'round', you are going to have to reprogram the SPI at both ends, adjust the TRIS register to match, and (if major current spikes are to be avoided), ensure that the changeover is done so that the lines switch to receive, ahead of the lines from the other end switching to transmit. This is complex, and full of danger. Take advantage of the bi-directional ability of the existing bus, and just have one master. If you want to 'trigger' the transfer from the other end, then use another line as a control signal.
If you want a 'multi-master' interface, save a wire, and use I2C. This is relatively much easier to reprogram.
Best Wishes |
|
|
|
|
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
|