Hi,
I am trying to get two GT16A MCUs to communicate via SPI, however I am not succeeding. The master is configured as shown below(SPI_Initialise), with the data sending being done in the laserComm function where Data[] is an array of unsigned char. Finally, the slave is configured as initSPI shows with the receiving done in the receiveSPI function. Any help would be appreciated!
void SPI_Initialise (void){ SPIBR = 0x00; // SPI baud rate = 9.437184MHz SPIC1_SPIE = 1; SPIC1_SPE = 1; SPIC1_SPTIE = 0; SPIC1_MSTR = 1; SPIC1_CPOL = 0; SPIC1_CPHA = 1; SPIC1_SSOE = 0; SPIC1_LSBFE = 0; //SPIC2 = 0x00; // SPI control register 2 setup SPIC2_MODFEN = 0; SPIC2_BIDIROE = 0; SPIC2_SPISWAI = 0; SPIC2_SPC0 = 0; } void laserComm(char Data[]){ int i; PTCD_PTCD6 = 0; //Pull low to select slave PTCD_PTCD5 = 0; //Pull low to select slave PTCD_PTCD4 = 0; //Pull low to select slave PTCD_PTCD3 = 0; //Pull low to select slave for(i = 0; i<=dataSize; i++){//send data while(!SPIS_SPTEF) SPID = Data[i++]; } PTCD_PTCD6 = 1; PTCD_PTCD5 = 1; PTCD_PTCD4 = 1; PTCD_PTCD3 = 1; } ///////// SLAVE //////////////// void initSPI (void){ SPIC1_SPIE = 1; // SPI control register 1 setup SPIC1_SPE = 1; // SPI enable SPIC1_SPTIE = 0; // Transmit interrupt enable SPIC1_MSTR = 0; // Slave select SPIC1_CPOL = 0; // Clock polarity SPIC1_CPHA = 1; // Clock phase SPIC1_SSOE = 0; // Slave select output enable SPIC1_LSBFE = 0; // LSB first disabled //SPIC2 = 0x00; // SPI control register 2 setup SPIC2_MODFEN = 0; SPIC2_BIDIROE = 0; SPIC2_SPISWAI = 0; SPIC2_SPC0 = 0; } interrupt 15 // SPI receive interrupt void receiveSPI (void){ int i; for (i = 0; i<=dataSize; i++) while(!SPIS_SPRF) SPIdataIn[i] = SPID; // Wait for receive buffer flag, read data SPIdataReceived = 1; }
Oliver, how is the project going?
Please let us know! :smileywink:
Regards!
Hello Oliver,
There seems to be a couple of issues with your master function.
void laserComm( char Data[])
{
int i;
PTCD_PTCD6 = 0; // Pull low to select slave
PTCD_PTCD5 = 0; // Pull low to select slave
PTCD_PTCD4 = 0; // Pull low to select slave
PTCD_PTCD3 = 0; // Pull low to select slave
for( i = 0; i <= dataSize; i++) { // send data
while( !SPIS_SPTEF) SPID = Data[i++];
}
PTCD_PTCD6 = 1;
PTCD_PTCD5 = 1;
PTCD_PTCD4 = 1;
PTCD_PTCD3 = 1;
}
The state of the flag SPIS_SPTEF is high when ready to send data, and goes low whenever the buffer is full. You are attempting to send the data when the flag is low. This condition can never occur within your code. The second problem is that you are potentially going to set the SS signals high before final byte tranfer has finished. To determine completion of transfer, you need to wait until the SPIS_SPRF flag is set. The corrected code follows -
void laserComm( char Data[])
{
int i;
PTCD_PTCD6 = 0; // Pull low to select slave
PTCD_PTCD5 = 0; // Pull low to select slave
PTCD_PTCD4 = 0; // Pull low to select slave
PTCD_PTCD3 = 0; // Pull low to select slave
for( i = 0; i <= dataSize; i++) {
while( !SPIS_SPTEF); // Wait until ready to send
SPID = Data[i++]; // send data byte
while( !SPIS_SPRF); // Wait until transfer is complete
(void)SPID; // Clear flag
}
PTCD_PTCD6 = 1;
PTCD_PTCD5 = 1;
PTCD_PTCD4 = 1;
PTCD_PTCD3 = 1;
}
The slave function also has some issues. I notice that you have a wait condition within your ISR code while you attempt to receive multiple bytes. It is normal to process only a single byte for each interrupt, to keep the ISR duration as short as possible.
You are also attempting to read the data when the flag is clear, and the transfer is incomplete. The interrupt will occur when the flag becomes set. You must clear the flag before exiting the ISR. There does seem to be a misunderstanding about the functionality of the flags.
The byte counter will need to be a static or global variable defined outside of the ISR function, and this will need to be initialised prior to each sequence. You will probably need to sense the state of the SS signal to determine when initialisation should occur.
Regards,
Mac
Hello Oliver,
The following untested code provides an example of the SPI slave process, using interrupts. I have assumed that the GPIO pin PTCD4 is paralleled with the SS pin (PTE2), for sensing the SS state.
#define SS_sig PTCD_PTCD4 // Additional input pin paralleled with SS
// Static variables:
static byte SPIdataIn[dataSize];
static byte count = 0;
byte Wait_for_SPIdata( void)
{
byte c;
if (SS_sig) return 0; // No data transfer yet
while (!SS_sig); // Wait for completion of transfer sequence
c = count; // Number of bytes transferred
count = 0; // Ready for next sequence
return c;
}
// SPI receive interrupt
interrupt 15 void receiveSPI( void)
{
(void)SPIS; // Commence clear flag
SPIdataIn[count++] = SPID; // Read data
}
Regards,
Mac
Hi,
First of all, at leaving reset all pins are GPIO IN, w/o pullups. The chip-select signals need to be outputs.
If it is so, then the problem seems to be with the topology used. If I understand correctly, as you pull 4 chipselects at the same time, you 're sending data to multiple slaves. they should have the MOSI pins connected parallel, not in the daisy chain fashion, like jtag chains.If it is so, then we need further examination of the software.
Hi, The code I posted above is a snippet from the main body, so the initialisation of the GPIO's isn't shown. The MOSI pins are connected in parallel and still I have no luck receiving data at the slave.
One thing I did notice when running the debugger is the interrupt for the slave is not triggered. Is the vector number for the interrupt correct?
Hi,
One more idea, when you do the write operations on the SPIC1, and SPIC2, in your code, you do it bit by bit, and the datasheet suggests, that this would be done bytewise, in other words, something like SPIC1 |= SPIE | SPE ...
...anyway...
I have set up an SPI master once, to receive , (I'm not a sw-expert, so please don't laugh, but) master controls look like this:
/*Some Init code for the peripherals*/
SOPT = 2; //Disable WD
ICGC2 = 0x08; //10MHz Crystal -> 40MHz Core, 20MHz Bus
ICGC1 = 0xFE;
PTCDD = 0x08; //PTC3 -> INT_ENAn(Out), PTC2 -> DIR_SEL(In)
PTDDD = 0x08; //PTD3 -> PWM(Out)
PTEDD = 0x04; //PTE2 -> SSn(Out)
PTCD = 0x08; //Disable IRQ
PTDD = 0x08; //PWM is active low, so off
PTED = 0x04; //SSn is active low, so off
SPIC1 =0x54; //Enable,Master Mode,CPHA=1
SPIC2 =0x00;
SPIBR =0x40; //CLK = (BUSCLK / 5) / 2 = 1MHz
TPM1SC = 0x48; //TPM1 will produce timing INT (int on every 1mS)(1kHz)
TPM1MODH = 0x4E; //Set the Modulo to be 20000
TPM1MODL = 0x20; //wich is req'd for 1kHz
TPM1C0VH = 0; //just to start up the timer
TPM1C0VL = 0; //Same reason
TPM1C0SC = TPM1C1SC = 0x00;
TPM2SC = 0x08; //TPM2 will be free-running PWM generator
TPM2MODH = 0x3F; //Set the Modulo to be 16383
TPM2MODL = 0xFF; //wich is req'd for 14bit res
TPM2C0SC = 0x24; //Low True Pulses
TPM2C0VH = 0; //Off for now...
TPM2C0VL = 0;
EnableInterrupts; /* enable interrupts */
...and in the interrupt routine, i give dummy bytes to the spi, to start transfer, but I only need the received bytes, anyway I suppose the sent bytes are out also...
...
PTED = 0x00; //Set SSn low,
for (aB = 0; aB < 2; aB++){ //Do it twice...
SPID = 0xFF; // Put 0xFF to SPID
bB = 0;// Wait for transfer to end
while (!(bB)) bB = (SPIS & 0x80);
SPIDataW = SPIDataW << 8;
SPIDataW += SPID; // Get the data from the SPID
};//...Until this line
PTED |= 0x04; //Set SSn high
...
This is how I handled the master, without irq unfortunately, but show some things...
Another question:
Could you confirm with an oscilloscope, that during transmission, data, and clk lines are toggling, or they are idle?
this can guide us towards finding the problem.