Thursday, February 8, 2024

PIC16F887 SPI and MCP23S17 XC8 Example

Overview

In previous post, I showed about the MSSP module of PIC16F887 with an SPI shift registers example. There are many SPI slave devices, a EEPROM memory, a GPIO extender chip, Flash memory, etc. 

PIC16F887 SPI and MCP23S17 XC8 Example
Program Simulation in Proteus

Here I use a MCP23S17 SPI GPIO expanding chip. The Microchip MCP23X17 series has two options of communication interfaces, the MCP23017 (I2C) and the MCP23S17(SPI). Both of them are bi-directional in data data transaction. 

PIC16F887 SPI and MCP23S17 XC8 Example
MCP23X17 Packaging Information


This chip has many package types including the Dual In Line Package (DIP-28) easing the prototyping for electronics hobbyists. I don't have the SPI communication interface of this chip. I have only one MCP23017 I2C one's.

PIC16F887 SPI and MCP23S17 XC8 Example
MCP23017 I2C Type

This chip can be used for LEDs or relays driving, keypad scanning, LCD driving, etc.

PIC16F887 SPI and MCP23S17 XC8 Example

Package Types

The SPI addressing mode is similar to the I2C mode. It uses a two-byte data package, device address, additional 3-bit addresses, and a read/write bit.

PIC16F887 SPI and MCP23S17 XC8 Example
Functional Block Diagram

For SPI mode (MCP23S17) has the following I/O pins.

  • Chip Select (CS) - Active low input signal latching data to its internal registers
  • Serial Clock (SCK) - input synchronous clock signal up to 10MHz
  • Serial Input (SI) - SPI serial data input (8-bit)
  • Serial Output (SO) - SPI serial data output (8-bit)

It has an additional 3-bit addresses (A2:A0). These address could be ignored or enable by software setting. By setting bit 3 of IOCON register we can enable this feature. By default this feature is ignored (A2:A0=0x00) and the memory addressing locates at BANK0 of the registers map.

Reset input (RESET) is active low. This pin can be shared with the micro-controller reset circuit.

GPIOA Interrupt (INTA) and GPIOB Interrupt (INTB) are the output signal notifying the master SPI whenever the input interrupt at GPIOA and GPIOB occurs. However this feature must be enable in its interrupt registers setting.

GPIOA (GPA) and GPIOB (GPB) are digital bi-directional readable/writable ports. Its data direction registers can be selected using the IODIRA and IODIRB registers. These registers will be shown in its registers map.

In SPI mode the clock rate has a maximum frequency of 10MHz. 

PIC16F887 SPI and MCP23S17 XC8 Example
SPI Addressing Registers

Its registers are divide into two banks, BANK0 and BANK1. By default BANK0 is active. So the programmer doesn't need to access BANK1 as it's not necessary. 

PIC16F887 SPI and MCP23S17 XC8 Example
Register Addressed

For a full details of these registers you can see its device datasheet. Here I will use only some registers to work with.

  • IODIRA - I/O DIRECTION REGISTER A (ADDR 0x00) : Clearing its bits for output direction, setting its bits for input direction.
  • IODIRB - I/O DIRECTION REGISTER B (ADDR 0x01) : Clearing its bits for output direction, setting its bits for input direction.
  • IOCONA - I/O EXPANDER CONFIGURATION REGISTER (ADDR 0x05)
  • IOCONB - I/O EXPANDER CONFIGURATION REGISTER (ADDR 0x06)
  • GPPUA -  GPIO PULL-UP RESISTOR REGISTER A(ADDR 0x0C)
  • GPPUB -  GPIO PULL-UP RESISTOR REGISTER B(ADDR 0x0D)
  • GPIOA -  GENERAL PURPOSE I/O PORT REGISTER A (ADDR 0x12)
  • GPIOB -  GENERAL PURPOSE I/O PORT REGISTER B (ADDR 0x13)
  • OLATA -  OUTPUT LATCH REGISTER A (ADDR 0x14)
  • OLATB -  OUTPUT LATCH REGISTER B (ADDR 0x15)

In this example we use use these registers in the MPLABX IDE and XC8 compiler. 

PIC16F887 MPLABX IDE and XC8 Programming

I use the high speed SPI communication interface of the MSSP module to interface with this chip. The MCP23S17 SPI slave chip is writable and readable.

GPIOA is configured as digital input reading input data from a DIP switch. GPIOB is configured as digital output writing data to the output LED. I turned on the pull up resistors of GPIOA to raise it high by default.

  1. /*
  2.  * File: main.c
  3.  * Author: Admin
  4.  *
  5.  * Created on February 9, 2024, 9:10 AM
  6.  */
  7.  
  8. #include <xc.h>
  9. #include "config.h"
  10. #include "spi.h"
  11.  
  12. #define _XTAL_FREQ 8000000UL
  13.  
  14. void mcp23S17_send(uint8_t address, uint8_t data){
  15. nCS=0;
  16. spi_send(WRITE_ADDR);
  17. spi_send(address);
  18. spi_send(data);
  19. nCS=1;
  20. }
  21.  
  22. uint8_t mcp23S17_receive(uint8_t address){
  23. uint8_t data;
  24. nCS=0;
  25. spi_send(READ_ADDR);
  26. spi_send(address);
  27. data=spi_receive();
  28. nCS=1;
  29. return data;
  30. }
  31.  
  32. void mcp23S17_init(void){
  33. nCS=1;
  34. mcp23S17_send(0x0A,0x08); // Enable Address Select
  35. mcp23S17_send(0x0B,0x08); // Enable Address Select
  36. mcp23S17_send(0x00,0xFF); // GPIOA AS INPUT
  37. mcp23S17_send(0x0C,0xFF); // Enable All GPPUA
  38. mcp23S17_send(0x01,0x00); // GPIOB AS OUTPUT
  39. }
  40.  
  41. void main(void) {
  42. uint8_t data;
  43. OSCCONbits.IRCF=7;
  44. spi_init();
  45. mcp23S17_init();
  46. while(1){
  47. data=mcp23S17_receive(0x12);
  48. mcp23S17_send(0x15,data);
  49. __delay_ms(150);
  50. }
  51. return;
  52. }
  53.  

I created a separate SPI driver in this project.

The SPI.h file:

  1. /*
  2.  * File: spi.h
  3.  * Author: Admin
  4.  *
  5.  * Created on February 9, 2024, 9:13 AM
  6.  */
  7.  
  8. #include <xc.h>
  9.  
  10. #define WRITE_ADDR 0x40
  11. #define READ_ADDR 0x41
  12.  
  13. #define nCS RC2
  14.  
  15. void spi_init(void);
  16. void spi_send(uint8_t data);
  17. uint8_t spi_receive(void);
  18.  
  19.  

 The SPI.c file:

  1.  
  2. #include "spi.h"
  3.  
  4. void spi_init(void){
  5. /*SPI Mode Clock Low To High*/
  6. SSPCONbits.CKP=0;
  7. SSPSTATbits.CKE=1;
  8. SSPSTATbits.SMP=0;
  9. /*SPI Master Mode Clock = Fosc/64*/
  10. SSPCONbits.SSPM=2;
  11. /*Turn On The Module*/
  12. SSPCONbits.SSPEN=1;
  13. SSPSTATbits.BF=1;
  14. PORTC=0;
  15. TRISC=0;
  16. /*SPI SDI Pin Input*/
  17. TRISC4=1;
  18. }
  19.  
  20. void spi_send(uint8_t data){
  21. SSPSTATbits.BF==1;
  22. SSPBUF=data;
  23. while(SSPSTATbits.BF==0);
  24. SSPSTATbits.BF==1;
  25. }
  26.  
  27. uint8_t spi_receive(void){
  28. uint8_t data;
  29. spi_send(0x00);
  30. data=SSPBUF;
  31. return data;
  32. }

Click here to download its source file.

PIC16F887 SPI and MCP23S17 XC8 Example
SPI Waveform

I use a virtual digital oscilloscope to get its waveform.




No comments:

Post a Comment

Search This Blog

Labels

25AA010A (1) 8051 (7) 93AA46B (1) ADC (30) Analog Comparator (1) Arduino (15) ARM (6) AT89C52 (7) ATMega32 (54) AVR (57) CCS PICC (28) DAC (1) DHT11 (2) Display (105) Distance Sensor (3) DS18B20 (3) dsPIC (2) dsPIC30F1010 (2) EEPROM (5) Environment Sensor (4) esp8266 (1) I2C (29) Input/Output (67) Interrupt (19) Keil (5) Keypad (10) LCD (46) Master/Slave (1) MAX7221 (1) MCP23017 (5) MCP23S17 (4) Meter (3) MikroC (2) Motor (15) MPLABX (66) Nokia 5110 LCD (3) OLED (2) One-Wire (6) Oscillator (8) PCB (6) PCD8544 (3) PCF8574 (5) PIC (107) PIC12F (2) PIC16F628A (2) PIC16F630 (1) PIC16F716 (3) PIC16F818 (10) PIC16F818/819 (2) PIC16F84A (15) PIC16F876A (1) PIC16F877A (9) PIC16F88 (1) PIC16F887 (60) PIC18 (19) PIC18F1220 (4) PIC18F2550 (3) PIC18F4550 (12) PWM (11) RTC (8) Sensor (10) SH1106 (1) Shift Register (11) Shift Registers (2) SPI (24) STM32 (6) STM32 Blue Pill (6) STM32CubeIDE (6) STM32F103C8T6 (6) SysTick (3) temperature sensor (11) Thermometer (21) Timer/Counter (30) TM1637 (2) UART (7) Ultrasonic (4) Voltmeter (7) WDT (1) XC16 (2) XC8 (94)