spi_master_revstring.c - SPI master uses slave to reverse stringsΒΆ

SPI example: PIC24 uC in Master mode talking to a PIC24 uC in slave mode, using the slave PIC24 uC (spi_slave_revstring.c - SPI slave reverse a string provided by a master) to reverse strings. The master expects the slave to assert a PIO output (SLAVE_ORDY in code) when a string has been reversed; the master then reads the string from the slave.

 
 
#include "pic24_all.h"

#define CONFIG_SLAVE_ENABLE() CONFIG_RB3_AS_DIG_OUTPUT()
#define SLAVE_ENABLE()      _LATB3 = 0  //low true assertion
#define SLAVE_DISABLE()     _LATB3 = 1

#define CONFIG_SLAVE_ORDY() CONFIG_RB2_AS_DIG_INPUT()
#define SLAVE_ORDY _RB2

void configSPI1(void) {
  SPI1CON1 =
#if (defined(__dsPIC33E__) || defined(__PIC24E__))
    //spi clock = 60MHz/1*6 = 60MHz/4 = 10MHz
    PRI_PRESCAL_1_1 |     //1:1 primary prescale
    SEC_PRESCAL_6_1 |     //6:1 secondary prescale
#else
    //spi clock = 40MHz/4*1 = 40MHz/4 = 10MHz
    PRI_PRESCAL_4_1 |     //4:1 primary prescale
    SEC_PRESCAL_1_1 |     //1:1 secondary prescale
#endif
    CLK_POL_ACTIVE_HIGH   | //clock active high (CKP = 0)
    SPI_CKE_OFF          | //out changes inactive to active (CKE=0)
    SPI_MODE8_ON        | //8-bit mode
    MASTER_ENABLE_ON;     //master mode
#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.
#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
#endif
  CONFIG_SLAVE_ENABLE();     //slave select config
  CONFIG_SLAVE_ORDY();       //output ready from slave
  SLAVE_DISABLE();           //disable slave
  SPI1STATbits.SPIEN = 1;    //enable SPI mode
}

typedef enum  {
  STATE_GET_IN_STRING = 0,
  STATE_GET_REV_STRING,
} STATE;

void sendStringSPI1(char* psz_s1) {
  SLAVE_ENABLE();
  while (*psz_s1) {
    ioMasterSPI1(*psz_s1);
    psz_s1++;
  }
  ioMasterSPI1(*psz_s1);  //send null terminator
  SLAVE_DISABLE();
}

void getStringSPI1(char* psz_s1, uint16_t u16_maxCount) {
  uint16_t u16_i = 0;
  if (!u16_maxCount) return;
  SLAVE_ENABLE();
  do {
    *psz_s1 = ioMasterSPI1(0);  //send dummy byte to get byte back
    psz_s1++;
    u16_i++;
  } while (*(psz_s1-1) && (u16_i <u16_maxCount));
  SLAVE_DISABLE();
  psz_s1--;
  *psz_s1 = 0; //ensure string is null terminated
}


#define BUFSIZE 63
char  sz_1[BUFSIZE+1];

int main (void) {
  STATE e_mystate;
  configBasic(HELLO_MSG);
  configSPI1();
  e_mystate = STATE_GET_IN_STRING;
  while (1) {
    switch (e_mystate) {
      case STATE_GET_IN_STRING:
        inStringEcho(sz_1,BUFSIZE);   //get a string from the console
        if (*sz_1) {
          sendStringSPI1(sz_1);
          e_mystate = STATE_GET_REV_STRING;
        }
        break;
      case STATE_GET_REV_STRING:
        if (SLAVE_ORDY) {
          getStringSPI1(sz_1,BUFSIZE+1);
          outString(sz_1);       //output the reversed string
          outString("\n");
          e_mystate = STATE_GET_IN_STRING;
        }
        break;
      default:
        e_mystate = STATE_GET_IN_STRING;
    }
    doHeartbeat();
  } //end switch
}