├── README.md ├── driver └── mcp23s17.c └── include └── driver ├── mcp23s17.h └── mcp23s17_register.h /README.md: -------------------------------------------------------------------------------- 1 | ESP8266 Microchip MCP23S17 Driver 2 | ======== 3 | 4 | Supports the Microchip MCP23S17 SPI I/O expanders. 5 | 6 | Enables the use of up to 128 additional GPIO pins through the SPI bus. 7 | 8 | Supports up to 8x MCP23S17 (16 GPIO) chips on the one SPI bus for a total of up to 128 GPIO pins. 9 | 10 | Mixing MCP23S08 and MCP23S17 chips on one bus is not currently supported. 11 | 12 | Requires my SPI driver: https://github.com/MetalPhreak/ESP8266_SPI_Driver -------------------------------------------------------------------------------- /driver/mcp23s17.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 David Ogilvy (MetalPhreak) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 26 | #include "driver/mcp23s17.h" 27 | 28 | #define SPI_DEV HSPI 29 | 30 | //////////////////////////////////////////////////////////////////////////////// 31 | // 32 | // Function Name: mcp23s17_init 33 | // Description: Initialises SPI hardware for 10MHz operation & configures 34 | // all attached MCP23S17 devices for individual addressing. 35 | // Parameters: none 36 | // 37 | //////////////////////////////////////////////////////////////////////////////// 38 | 39 | void mcp23s17_init(){ 40 | //init SPI bus 41 | spi_init_gpio(SPI_DEV, SPI_CLK_USE_DIV); 42 | spi_clock(SPI_DEV, 4, 2); //10MHz 43 | spi_tx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW); 44 | spi_rx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW); 45 | 46 | SET_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_CS_SETUP|SPI_CS_HOLD); 47 | CLEAR_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_FLASH_MODE); 48 | 49 | //Enable hardware addressing & sequential addressing on all devices 50 | mcp23s17_REG_SET(IOCON_CTRL, PORTA, SEQOP|HAEN); 51 | 52 | } 53 | 54 | //////////////////////////////////////////////////////////////////////////////// 55 | 56 | //////////////////////////////////////////////////////////////////////////////// 57 | // 58 | // Function Name: mcp23s17_REG_SET 59 | // Description: Set register value 60 | // Parameters: ctrl_reg - control register to set 61 | // port - port to control 62 | // value - value to set 63 | // 64 | //////////////////////////////////////////////////////////////////////////////// 65 | 66 | void mcp23s17_REG_SET(uint8 ctrl_reg, uint8 port, uint16 value){ 67 | 68 | uint8 cmd = (0x20|(port>>2))<<1; //0b0100[Address][WRITE] 69 | 70 | if (port & 0x02){ 71 | spi_transaction(SPI_DEV, 8, cmd, 8, ctrl_reg, 16, value, 0, 0); 72 | } else { 73 | spi_transaction(SPI_DEV, 8, cmd, 8, ctrl_reg+(port&0x01), 8, value, 0, 0); 74 | } 75 | } 76 | 77 | //////////////////////////////////////////////////////////////////////////////// 78 | 79 | //////////////////////////////////////////////////////////////////////////////// 80 | // 81 | // Function Name: mcp23s17_REG_GET 82 | // Description: Get register value 83 | // Parameters: ctrl_reg - control register to get 84 | // port - port to control 85 | // 86 | //////////////////////////////////////////////////////////////////////////////// 87 | 88 | uint16 mcp23s17_REG_GET(uint8 ctrl_reg, uint8 port){ 89 | 90 | uint8 cmd = ((0x20|(port>>2))<<1)|0x01; //0b0100[Address][READ] 91 | 92 | if (port & 0x02){ 93 | return spi_transaction(SPI_DEV, 8, cmd, 8, ctrl_reg, 0, 0, 16, 0); 94 | } else { 95 | return (uint16) spi_transaction(SPI_DEV, 8, cmd, 8, ctrl_reg+(port&0x01), 0, 0, 8, 0); 96 | } 97 | } 98 | 99 | //////////////////////////////////////////////////////////////////////////////// 100 | 101 | //////////////////////////////////////////////////////////////////////////////// 102 | // 103 | // Function Name: mcp23s17_REG_SET_MASK 104 | // Description: Set register value bits with a mask 105 | // Parameters: ctrl_reg - control register to set 106 | // port - port to control 107 | // value - value to set 108 | // bitmask - which bits to change 109 | // 110 | //////////////////////////////////////////////////////////////////////////////// 111 | 112 | void mcp23s17_REG_SET_MASK(uint8 ctrl_reg, uint8 port, uint16 value, uint16 bitmask){ 113 | 114 | uint16 current_value = ~bitmask & mcp23s17_REG_GET(ctrl_reg, port); 115 | uint16 set_value = bitmask & value; 116 | 117 | mcp23s17_REG_SET(ctrl_reg, port, current_value|set_value); 118 | 119 | } 120 | 121 | //////////////////////////////////////////////////////////////////////////////// 122 | 123 | /*/////////////////////////////////////////////////////////////////////////////// 124 | // 125 | // Function Name: func 126 | // Description: 127 | // Parameters: 128 | // 129 | //////////////////////////////////////////////////////////////////////////////// 130 | 131 | void func(params){ 132 | 133 | } 134 | 135 | ///////////////////////////////////////////////////////////////////////////////*/ 136 | 137 | 138 | -------------------------------------------------------------------------------- /include/driver/mcp23s17.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 David Ogilvy (MetalPhreak) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef MCP23S17_H 26 | #define MCP23S17_H 27 | 28 | #include "driver/spi.h" 29 | #include "driver/mcp23s17_register.h" 30 | 31 | 32 | void mcp23s17_init(); 33 | void mcp23s17_REG_SET(uint8 ctrl_reg, uint8 port, uint16 value); 34 | uint16 mcp23s17_REG_GET(uint8 ctrl_reg, uint8 port); 35 | void mcp23s17_REG_SET_MASK(uint8 ctrl_reg, uint8 port, uint16 value, uint16 bitmask); 36 | 37 | #define sGPIO_SET(port, value) mcp23s17_REG_SET(OLAT_CTRL, port, value) 38 | #define sGPIO_SET_MASK(port, value, bitmask) mcp23s17_REG_SET_MASK(OLAT_CTRL, port, value, bitmask) 39 | #define sGPIO_SET_PIN(port, pin, value) mcp23s17_REG_SET_MASK(OLAT_CTRL, port, value<<(pin-1), 1<<(pin-1)) 40 | 41 | #define sGPIO_GET(port) mcp23s17_REG_GET(OLAT_CTRL, port) 42 | 43 | #define sGPIO_READ(port) mcp23s17_REG_GET(GPIO_CTRL, port) 44 | 45 | 46 | 47 | 48 | 49 | 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /include/driver/mcp23s17_register.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 David Ogilvy (MetalPhreak) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef MCP23S17_REGISTER_H 26 | #define MCP23S17_REGISTER_H 27 | 28 | // 0b000ADDMP 29 | // | |^^ Port: 0 = PORTA#; 1 = PORTB#; x = Don't Care for 16bit I/O Setup 30 | // ^ ^ Mode: 0 = 8bit; 1 = 16bit 31 | // ^ Device ADDress: 000 = Chip 0, 001 = Chip 1 ... 111 = Chip 7 32 | 33 | #define PORTA0 0x00 34 | #define PORTB0 0x01 35 | #define PORT0 0x02 36 | 37 | #define PORTA1 0x04 38 | #define PORTB1 0x05 39 | #define PORT1 0x06 40 | 41 | #define PORTA2 0x08 42 | #define PORTB2 0x09 43 | #define PORT2 0x0A 44 | 45 | #define PORTA3 0x0C 46 | #define PORTB3 0x0D 47 | #define PORT3 0x0E 48 | 49 | #define PORTA4 0x10 50 | #define PORTB4 0x11 51 | #define PORT4 0x12 52 | 53 | #define PORTA5 0x14 54 | #define PORTB5 0x15 55 | #define PORT5 0x16 56 | 57 | #define PORTA6 0x18 58 | #define PORTB6 0x19 59 | #define PORT6 0x1A 60 | 61 | #define PORTA7 0x1C 62 | #define PORTB7 0x1D 63 | #define PORT7 0x1E 64 | 65 | //If you only have one device, you can use the below for simplicity. 66 | //Connect all address pins to ground, or change the below defines to match your address setting. 67 | #define PORTA PORTA0 68 | #define PORTB PORTB0 69 | #define PORT PORT0 70 | 71 | #define GPIO0 0x0001 72 | #define GPIO1 0x0002 73 | #define GPIO2 0x0004 74 | #define GPIO3 0x0008 75 | #define GPIO4 0x0010 76 | #define GPIO5 0x0020 77 | #define GPIO6 0x0040 78 | #define GPIO7 0x0080 79 | #define GPIO8 0x0100 80 | #define GPIO9 0x0200 81 | #define GPIO10 0x0400 82 | #define GPIO11 0x0800 83 | #define GPIO12 0x1000 84 | #define GPIO13 0x2000 85 | #define GPIO14 0x4000 86 | #define GPIO15 0x8000 87 | 88 | //IOCON.Bank = 0 by default on startup which is better for using 16bit mode (and just as good for 8bit) 89 | 90 | //These control register maps are valid only when IOCON.Bank = 0! 91 | 92 | //Can use these only with PORTAx/PORTBx respectively 93 | #define IODIRA 0x00 94 | #define IODIRB 0x01 95 | #define IPOLA 0x02 96 | #define IPOLB 0x03 97 | #define GPINTENA 0x04 98 | #define GPINTENB 0x05 99 | #define DEFVALA 0x06 100 | #define DEFVALB 0x07 101 | #define INTCONA 0x08 102 | #define INTCONB 0x09 103 | #define IOCONA 0x0A 104 | #define IOCONB 0x0B 105 | #define GPPUA 0x0C 106 | #define GPPUB 0x0D 107 | #define INTFA 0x0E 108 | #define INTFB 0x0F 109 | #define INTCAPA 0x10 110 | #define INTCAPB 0x11 111 | #define GPIOA 0x12 112 | #define GPIOB 0x13 113 | #define OLATA 0x14 114 | #define OLATB 0x15 115 | 116 | //Can use these names for control registers for all PORTAx/PORTBx/PORTx 117 | #define IODIR_CTRL 0x00 118 | #define IPOL_CTRL 0x02 119 | #define GPINTEN_CTRL 0x04 120 | #define DEFVAL_CTRL 0x06 121 | #define INTCON_CTRL 0x08 122 | #define IOCON_CTRL 0x0A 123 | #define GPPU_CTRL 0x0C 124 | #define INTF_CTRL 0x0E 125 | #define INTCAP_CTRL 0x10 126 | #define GPIO_CTRL 0x12 127 | #define OLAT_CTRL 0x14 128 | 129 | 130 | //IOCON bits 131 | #define INTPOL 0x02 132 | #define ODR 0x04 133 | #define HAEN 0x08 134 | #define DISSLW 0x10 135 | #define SEQOP 0x20 136 | #define MIRROR 0x40 137 | #define BANK 0x80 138 | 139 | #endif 140 | 141 | --------------------------------------------------------------------------------