/********************************************************************\ Name: gpio.c Created by: Stefan Ritt Contents: Driver for MCP23S17 General Purpose IO Chip \********************************************************************/ #include #include #include #include #include "mscbemb.h" #include "mpdc.h" // register addresses for non-banked layout (bank=0) #define GPIO_IODIRA 0x00 #define GPIO_IODIRB 0x01 #define GPIO_IPOLA 0x02 #define GPIO_IPOLB 0x03 #define GPIO_GPINTENA 0x04 #define GPIO_GPINTENB 0x05 #define GPIO_DEFVALA 0x06 #define GPIO_DEFVALB 0x07 #define GPIO_INTCONA 0x08 #define GPIO_INTCONB 0x09 #define GPIO_IOCON 0x0A #define GPIO_GPPUA 0x0C #define GPIO_GPPUB 0x0D #define GPIO_INTFA 0x0E #define GPIO_INTFB 0x0F #define GPIO_INTCAPA 0x10 #define GPIO_INTCAPB 0x11 #define GPIO_GPIOA 0x12 #define GPIO_GPIOB 0x13 #define GPIO_OLATA 0x14 #define GPIO_OLATB 0x15 /*------------------------------------------------------------------*/ sbit RST_SR = P1 ^ 0; unsigned char pd[12]; unsigned char gpio_mask[12]; unsigned char gpio_inp[12]; void gpio_init() { unsigned char i; // remove RST_SR SFRPAGE = LEGACY_PAGE; RST_SR = 0; // calculate port direction bits memset(pd, 0, sizeof(pd)); for (i=0 ; i<32 ; i++) pd[(i * 3) / 8] |= (1 << ((i * 3) % 8)); // initialize output bit mask for (i=0 ; i<12 ; i++) gpio_mask[i] = 0; for (i = 0 ; i < 6 ; i++) { gpio_write(i, GPIO_IOCON, 1<<3); // HAEN = 1, addresses all four devices gpio_write(i, GPIO_IODIRA, ~pd[i*2]); // 1=output, so invert bits gpio_write(i, GPIO_IODIRB, ~pd[i*2+1]); } } /*------------------------------------------------------------------*/ void gpio_write(unsigned char device, unsigned char adr, unsigned char d) { // Device 0,1,2: IO Expander 1, 3,4,5: IO Expander 2 spi_adr(device < 3 ? ADR_GPIO1 : ADR_GPIO2); if (device >= 3) device += 5; // Device opcode 0x40 combined with 3-bit hardware address, R/W = 0 (=write) spi_write_msb(0x40 | ((device & 0x07) << 1)); spi_write_msb(adr); spi_write_msb(d); spi_deadr(); } /*------------------------------------------------------------------*/ unsigned char gpio_read(unsigned char device, unsigned char adr) { unsigned char d; // Device 0,1,2: IO Expander 1, 3,4,5: IO Expander 2 spi_adr(device < 3 ? ADR_GPIO1 : ADR_GPIO2); if (device >= 3) device -= 3; // Put addresses back to 0...2 // Device opcode 0x40 combined 3-bit hardware address, R/W = 1 (=read) spi_write_msb(0x40 | ((device & 0x07) << 1) | 0x01); spi_write_msb(adr); d = spi_read_msb(); spi_deadr(); return d; } /*------------------------------------------------------------------*/ /* turn channel on or off */ void gpio_channel_on(unsigned char channel, unsigned char flag) { unsigned char p, o, a; a = (channel * 3) / 16; // address 0 ... 5 p = (channel * 3) / 8; // port 0 ... 11 o = (channel * 3) % 8; // bit offset 0 ... 7 if (flag == 1) gpio_mask[p] |= (1 << o); else gpio_mask[p] &= ~(1 << o); gpio_write(a, (p % 2 == 0) ? GPIO_OLATA : GPIO_OLATB, gpio_mask[p]); } /*------------------------------------------------------------------*/ void gpio_get_status(unsigned char *s) { unsigned char i, p, o; // read all ports for (i=0 ; i<12 ; i++) gpio_inp[i] = gpio_read(i / 2, (i % 2 == 0) ? GPIO_GPIOA : GPIO_GPIOB); // extract power good bits for (i=0 ; i<32 ; i++) { p = (i*3 + 1) / 8; // port 0 ... 11 o = (i*3 + 1) % 8; // bit offset 0 ... 7 if (gpio_inp[p] & (1 << o)) s[i] |= (1 << 1); // set bit 1 else s[i] &= ~(1 << 1); // clear bit 1 } // extract fault bits for (i=0 ; i<32 ; i++) { p = (i*3 + 2) / 8; // port 0 ... 11 o = (i*3 + 2) % 8; // bit offset 0 ... 7 if ((gpio_inp[p] & (1 << o)) == 0) // FLTB is inverted! s[i] |= (1 << 2); // set bit 2 else s[i] &= ~(1 << 2); // clear bit 2 } }