spi_slave_revstring.c - SPI slave reverse a string provided by a masterΒΆ
SPI example: PIC24 uC in slave mode talking to PIC24 uC in master mode (see spi_master_revstring.c - SPI master uses slave to reverse strings), which is using this slave PIC24 uC to reverse strings.
#include "pic24_all.h"
void reverseString(volatile char *psz_s1, volatile char *psz_s2);
#define CONFIG_SLAVE_ORDY() CONFIG_RB2_AS_DIG_OUTPUT()
#define SLAVE_ORDY _LATB2
typedef enum {
STATE_WAIT_FOR_STRING,
STATE_SEND_REV_STRING,
STATE_LAST_REVCHAR_STRING,
} STATE;
volatile STATE e_mystate = STATE_WAIT_FOR_STRING;
#define BUFSIZE 63
volatile char sz_1[BUFSIZE+1];
volatile char sz_2[BUFSIZE+1];
volatile uint16_t u16_index;
void _ISR _SPI1Interrupt (void) {
uint16_t u16_tmp;
switch (e_mystate) {
case STATE_WAIT_FOR_STRING:
//character arrived, place in buffer
sz_1[u16_index] = SPI1BUF;
u16_index++;
if (sz_1[u16_index-1] == 0) {
//have a complete string, reverse it.
reverseString(sz_1,sz_2);
//place first character of reversed string in SPIBUF
u16_index = 0;
SPI1BUF = sz_2[u16_index];
u16_index++;
SLAVE_ORDY = 1; //indicate to MASTER that reversed string is ready
e_mystate = STATE_SEND_REV_STRING;
}
break;
case STATE_SEND_REV_STRING:
u16_tmp = SPI1BUF; //must read the SPIBUF to prevent overflow, discard it.
//just keep placing reversed characters in buffer as MASTER reads our SPI port
SPI1BUF = sz_2[u16_index];
u16_index++;
if (sz_2[u16_index-1] == 0) {
//this is the last character, no more data
SLAVE_ORDY = 0;
e_mystate = STATE_LAST_REVCHAR_STRING;
}
break;
case STATE_LAST_REVCHAR_STRING:
u16_index = 0;
u16_tmp = SPI1BUF; //must read the SPIBUF to prevent overflow, discard it.
//null terminator of reversed string just read, wait for next string
e_mystate = STATE_WAIT_FOR_STRING;
break;
default:
e_mystate = STATE_WAIT_FOR_STRING;
}
_SPI1IF = 0; //clear interrupt flag
}
void reverseString(volatile char *psz_s1, volatile char *psz_s2) {
volatile char *psz_s1end;
if (!(*psz_s1)) {
*psz_s2 = 0; //psz_s1 is empty, return.
return;
}
psz_s1end = psz_s1;
//find end of first string
while (*psz_s1end) psz_s1end++;
psz_s1end--; //backup one to first non-zero byte
//now copy to S2 in reverse order
while (psz_s1end != psz_s1) {
*psz_s2 = *psz_s1end;
psz_s1end--;
psz_s2++;
}
//copy last byte
*psz_s2 = *psz_s1end;
psz_s2++;
//mark end of string
*psz_s2 = 0;
}
void configSPI1(void) {
//no need for prescaler since master supplies the clock
SPI1CON1 = CLK_POL_ACTIVE_HIGH |
SPI_CKE_OFF |
SLAVE_ENABLE_ON |
SPI_MODE8_ON |
MASTER_ENABLE_OFF;
//configure pins
#if (defined(__dsPIC33E__) || defined(__PIC24E__))
//nothing to do here. On this family, the SPI1 port uses dedicated
//pins for higher speed. The SPI2 port can be used with remappable pins.
//you may need to add code to disable analog functionality if the SPI ports
//are on analog-capable pins.
#else
CONFIG_SDO1_TO_RP(RB6_RP); //use RB6 for SDO
CONFIG_RB6_AS_DIG_OUTPUT(); //Ensure that this is a digital output
CONFIG_SCK1OUT_TO_RP(RB7_RP); //use RB7 for SCLK
CONFIG_RB7_AS_DIG_INPUT(); //Ensure that this is a digital input
CONFIG_SDI1_TO_RP(RB5_RP); //use RP5 for SDI
CONFIG_RB5_AS_DIG_INPUT(); //Ensure that this is a digital input
CONFIG_SS1IN_TO_RP(RB3_RP); //use RP3 for SS#
CONFIG_RB3_AS_DIG_OUTPUT(); //Ensure that this is a digital output
#endif
CONFIG_SLAVE_ORDY(); //handshake to indicate output ready
SLAVE_ORDY = 0; //output is not ready
u16_index = 0; //no data yet
_SPI1IF = 0; //clear the flag
_SPI1IP = 3; //choose a priority
_SPI1IE = 1; //enable the interrupt
SPI1STATbits.SPIROV = 0; //clear overflow flag
SPI1STATbits.SPIEN = 1; //enable SPI mode
}
int main (void) {
configClock(); //no UART for slave
configHeartbeat();
configSPI1();
while (1) doHeartbeat();
}