The iPod controller that I submitted for the mbed challenge
Dependencies: mbed Motordriver PID
user_interface/MCP23017.cpp@0:371773dd3dd1, 2011-05-04 (annotated)
- Committer:
- networker
- Date:
- Wed May 04 15:41:13 2011 +0000
- Revision:
- 0:371773dd3dd1
first publication
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
networker | 0:371773dd3dd1 | 1 | /* MCP23017 - drive the Microchip MCP23017 16-bit Port Extender using I2C |
networker | 0:371773dd3dd1 | 2 | * Copyright (c) 2010 Wim Huiskamp, Romilly Cocking (original version for SPI) |
networker | 0:371773dd3dd1 | 3 | * |
networker | 0:371773dd3dd1 | 4 | * Released under the MIT License: http://mbed.org/license/mit |
networker | 0:371773dd3dd1 | 5 | * |
networker | 0:371773dd3dd1 | 6 | * version 0.2 Initial Release |
networker | 0:371773dd3dd1 | 7 | * version 0.3 Cleaned up |
networker | 0:371773dd3dd1 | 8 | */ |
networker | 0:371773dd3dd1 | 9 | |
networker | 0:371773dd3dd1 | 10 | #include "mbed.h" |
networker | 0:371773dd3dd1 | 11 | #include "MCP23017.h" |
networker | 0:371773dd3dd1 | 12 | |
networker | 0:371773dd3dd1 | 13 | DigitalOut Busy(LED4); |
networker | 0:371773dd3dd1 | 14 | |
networker | 0:371773dd3dd1 | 15 | /** Create an MCP23017 object connected to the specified I2C object and using the specified deviceAddress |
networker | 0:371773dd3dd1 | 16 | * |
networker | 0:371773dd3dd1 | 17 | * @param I2C &i2c the I2C port to connect to |
networker | 0:371773dd3dd1 | 18 | * @param char deviceAddress the address of the MSC23017 |
networker | 0:371773dd3dd1 | 19 | */ |
networker | 0:371773dd3dd1 | 20 | MCP23017::MCP23017(I2C &i2c, char deviceAddress) : _i2c(i2c) { |
networker | 0:371773dd3dd1 | 21 | printf("creating mcp23017\n"); |
networker | 0:371773dd3dd1 | 22 | _writeOpcode = deviceAddress & 0xFE; // low order bit = 0 for write |
networker | 0:371773dd3dd1 | 23 | _readOpcode = deviceAddress | 0x01; // low order bit = 1 for read |
networker | 0:371773dd3dd1 | 24 | busy = false; |
networker | 0:371773dd3dd1 | 25 | posted = false; |
networker | 0:371773dd3dd1 | 26 | _init(); |
networker | 0:371773dd3dd1 | 27 | readW(INTFA); |
networker | 0:371773dd3dd1 | 28 | readW(GPIOA); |
networker | 0:371773dd3dd1 | 29 | printf("mcp23017 created\n"); |
networker | 0:371773dd3dd1 | 30 | } |
networker | 0:371773dd3dd1 | 31 | |
networker | 0:371773dd3dd1 | 32 | /** Read from specified MCP23017 register |
networker | 0:371773dd3dd1 | 33 | * |
networker | 0:371773dd3dd1 | 34 | * @param char address the internal registeraddress of the MSC23017 |
networker | 0:371773dd3dd1 | 35 | * @returns data from register |
networker | 0:371773dd3dd1 | 36 | */ |
networker | 0:371773dd3dd1 | 37 | short MCP23017::_read(char address) {//blocks on busy and still waits for completion |
networker | 0:371773dd3dd1 | 38 | char data[2]; |
networker | 0:371773dd3dd1 | 39 | i2c_status s; |
networker | 0:371773dd3dd1 | 40 | data[0] = address; |
networker | 0:371773dd3dd1 | 41 | do { |
networker | 0:371773dd3dd1 | 42 | s = _read(address, data, 1); |
networker | 0:371773dd3dd1 | 43 | } while (s == i2c_busy); |
networker | 0:371773dd3dd1 | 44 | return (s == i2c_ok) ? data[0] : -2; |
networker | 0:371773dd3dd1 | 45 | } |
networker | 0:371773dd3dd1 | 46 | |
networker | 0:371773dd3dd1 | 47 | MCP23017::i2c_status MCP23017::_read(char reg, char *data, int size) {//returns on busy but still waits for completion |
networker | 0:371773dd3dd1 | 48 | if (testbusy()) return i2c_busy; |
networker | 0:371773dd3dd1 | 49 | _i2c.write(_writeOpcode, ®, 1, true); //in a future version of the i2c lib write should return a status like ACK or NACK or busy |
networker | 0:371773dd3dd1 | 50 | int result = _i2c.read(_readOpcode, data, size); |
networker | 0:371773dd3dd1 | 51 | releasebusy(); |
networker | 0:371773dd3dd1 | 52 | return result ? i2c_nack : i2c_ok; |
networker | 0:371773dd3dd1 | 53 | } |
networker | 0:371773dd3dd1 | 54 | |
networker | 0:371773dd3dd1 | 55 | int MCP23017::readW(char address) {//blocks on busy and still waits for completion |
networker | 0:371773dd3dd1 | 56 | char data[2]; |
networker | 0:371773dd3dd1 | 57 | i2c_status s; |
networker | 0:371773dd3dd1 | 58 | data[0] = address; |
networker | 0:371773dd3dd1 | 59 | do { |
networker | 0:371773dd3dd1 | 60 | s = _read(address, data, 2); |
networker | 0:371773dd3dd1 | 61 | } while (s == i2c_busy); |
networker | 0:371773dd3dd1 | 62 | return (s == i2c_ok) ? *(unsigned short*)data : -1; |
networker | 0:371773dd3dd1 | 63 | } |
networker | 0:371773dd3dd1 | 64 | |
networker | 0:371773dd3dd1 | 65 | |
networker | 0:371773dd3dd1 | 66 | /** Write to specified MCP23017 register |
networker | 0:371773dd3dd1 | 67 | * |
networker | 0:371773dd3dd1 | 68 | * @param char address the internal registeraddress of the MSC23017 |
networker | 0:371773dd3dd1 | 69 | */ |
networker | 0:371773dd3dd1 | 70 | void MCP23017::_write(char address, char byte) {//blocks on busy and still waits for completion |
networker | 0:371773dd3dd1 | 71 | i2c_status s; |
networker | 0:371773dd3dd1 | 72 | char data[2]; |
networker | 0:371773dd3dd1 | 73 | data[0] = address; |
networker | 0:371773dd3dd1 | 74 | data[1] = byte; |
networker | 0:371773dd3dd1 | 75 | do { |
networker | 0:371773dd3dd1 | 76 | s = _write(data, 2); |
networker | 0:371773dd3dd1 | 77 | } while (s == i2c_busy); |
networker | 0:371773dd3dd1 | 78 | // _i2c.write(_writeOpcode, data, 2); // Write data to selected Register |
networker | 0:371773dd3dd1 | 79 | return ; //s; //in the future return the status |
networker | 0:371773dd3dd1 | 80 | } |
networker | 0:371773dd3dd1 | 81 | |
networker | 0:371773dd3dd1 | 82 | MCP23017::i2c_status MCP23017::_write(char *data, int size, bool rpt) {//returns on busy but still waits for completion |
networker | 0:371773dd3dd1 | 83 | if (testbusy()) return i2c_busy; |
networker | 0:371773dd3dd1 | 84 | int result = 0; |
networker | 0:371773dd3dd1 | 85 | _i2c.write(_writeOpcode, data, size, rpt); // Write data to selected Register |
networker | 0:371773dd3dd1 | 86 | releasebusy(); |
networker | 0:371773dd3dd1 | 87 | return result ? i2c_nack : i2c_ok; |
networker | 0:371773dd3dd1 | 88 | } |
networker | 0:371773dd3dd1 | 89 | |
networker | 0:371773dd3dd1 | 90 | /** Init MCP23017 |
networker | 0:371773dd3dd1 | 91 | * |
networker | 0:371773dd3dd1 | 92 | * @param |
networker | 0:371773dd3dd1 | 93 | * @returns |
networker | 0:371773dd3dd1 | 94 | */ |
networker | 0:371773dd3dd1 | 95 | void MCP23017::_init() { |
networker | 0:371773dd3dd1 | 96 | _write(IOCON, (IOCON_BYTE_MODE | IOCON_ODR )); // Open drain interrupt, operations toggle between A and B registers |
networker | 0:371773dd3dd1 | 97 | |
networker | 0:371773dd3dd1 | 98 | } |
networker | 0:371773dd3dd1 | 99 | |
networker | 0:371773dd3dd1 | 100 | /** Set I/O direction of specified MCP23017 Port |
networker | 0:371773dd3dd1 | 101 | * |
networker | 0:371773dd3dd1 | 102 | * @param Port Port address (Port_A or Port_B) |
networker | 0:371773dd3dd1 | 103 | * @param char direction pin direction (0 = output, 1 = input) |
networker | 0:371773dd3dd1 | 104 | */ |
networker | 0:371773dd3dd1 | 105 | void MCP23017::direction(Port port, char direction) { |
networker | 0:371773dd3dd1 | 106 | _write(port + IODIRA, direction); |
networker | 0:371773dd3dd1 | 107 | } |
networker | 0:371773dd3dd1 | 108 | |
networker | 0:371773dd3dd1 | 109 | /** Set Pull-Up Resistors on specified MCP23017 Port |
networker | 0:371773dd3dd1 | 110 | * |
networker | 0:371773dd3dd1 | 111 | * @param Port Port address (Port_A or Port_B) |
networker | 0:371773dd3dd1 | 112 | * @param char offOrOn per pin (0 = off, 1 = on) |
networker | 0:371773dd3dd1 | 113 | */ |
networker | 0:371773dd3dd1 | 114 | void MCP23017::configurePullUps(Port port, char offOrOn) { |
networker | 0:371773dd3dd1 | 115 | _write(port + GPPUA, offOrOn); |
networker | 0:371773dd3dd1 | 116 | } |
networker | 0:371773dd3dd1 | 117 | |
networker | 0:371773dd3dd1 | 118 | void MCP23017::interruptEnable(Port port, char interruptsEnabledMask) { |
networker | 0:371773dd3dd1 | 119 | _write(port + GPINTENA, interruptsEnabledMask); |
networker | 0:371773dd3dd1 | 120 | } |
networker | 0:371773dd3dd1 | 121 | |
networker | 0:371773dd3dd1 | 122 | void MCP23017::mirrorInterrupts(bool mirror) { |
networker | 0:371773dd3dd1 | 123 | char iocon = _read(IOCON); |
networker | 0:371773dd3dd1 | 124 | if (mirror) { |
networker | 0:371773dd3dd1 | 125 | iocon = iocon | INTERRUPT_MIRROR_BIT; |
networker | 0:371773dd3dd1 | 126 | } else { |
networker | 0:371773dd3dd1 | 127 | iocon = iocon & ~INTERRUPT_MIRROR_BIT; |
networker | 0:371773dd3dd1 | 128 | } |
networker | 0:371773dd3dd1 | 129 | _write(IOCON, iocon); |
networker | 0:371773dd3dd1 | 130 | |
networker | 0:371773dd3dd1 | 131 | } |
networker | 0:371773dd3dd1 | 132 | |
networker | 0:371773dd3dd1 | 133 | void MCP23017::interruptPolarity(Polarity polarity) { |
networker | 0:371773dd3dd1 | 134 | char iocon = _read(IOCON); |
networker | 0:371773dd3dd1 | 135 | if (polarity == ACTIVE_LOW) { |
networker | 0:371773dd3dd1 | 136 | iocon = iocon & ~INTERRUPT_POLARITY_BIT; |
networker | 0:371773dd3dd1 | 137 | } else { |
networker | 0:371773dd3dd1 | 138 | iocon = iocon | INTERRUPT_POLARITY_BIT; |
networker | 0:371773dd3dd1 | 139 | } |
networker | 0:371773dd3dd1 | 140 | _write(IOCON, iocon); |
networker | 0:371773dd3dd1 | 141 | } |
networker | 0:371773dd3dd1 | 142 | |
networker | 0:371773dd3dd1 | 143 | void MCP23017::defaultValue(Port port, char valuesToCompare) { |
networker | 0:371773dd3dd1 | 144 | _write(port + DEFVALA, valuesToCompare); |
networker | 0:371773dd3dd1 | 145 | } |
networker | 0:371773dd3dd1 | 146 | |
networker | 0:371773dd3dd1 | 147 | void MCP23017::interruptControl(Port port, char interruptControlBits) { |
networker | 0:371773dd3dd1 | 148 | _write(port + INTCONA, interruptControlBits); |
networker | 0:371773dd3dd1 | 149 | } |
networker | 0:371773dd3dd1 | 150 | |
networker | 0:371773dd3dd1 | 151 | /** Write to specified MCP23017 Port |
networker | 0:371773dd3dd1 | 152 | * |
networker | 0:371773dd3dd1 | 153 | * @param Port Port address (Port_A or Port_B) |
networker | 0:371773dd3dd1 | 154 | * @param char byte data to write |
networker | 0:371773dd3dd1 | 155 | */ |
networker | 0:371773dd3dd1 | 156 | void MCP23017::write(Port port, char byte) { |
networker | 0:371773dd3dd1 | 157 | _write(port + OLATA, byte); |
networker | 0:371773dd3dd1 | 158 | } |
networker | 0:371773dd3dd1 | 159 | |
networker | 0:371773dd3dd1 | 160 | /** Read from specified MCP23017 Port |
networker | 0:371773dd3dd1 | 161 | * |
networker | 0:371773dd3dd1 | 162 | * @param Port Port address (Port_A or Port_B) |
networker | 0:371773dd3dd1 | 163 | * @returns data from Port |
networker | 0:371773dd3dd1 | 164 | */ |
networker | 0:371773dd3dd1 | 165 | char MCP23017::read(Port port) { |
networker | 0:371773dd3dd1 | 166 | return _read(port + GPIOA); |
networker | 0:371773dd3dd1 | 167 | } |
networker | 0:371773dd3dd1 | 168 | |
networker | 0:371773dd3dd1 | 169 | void MCP23017::write(Port port, const char *buffer, int len, bool rpt) { |
networker | 0:371773dd3dd1 | 170 | len++; |
networker | 0:371773dd3dd1 | 171 | char *data = new char[len]; |
networker | 0:371773dd3dd1 | 172 | data[0] = port+OLATA; |
networker | 0:371773dd3dd1 | 173 | i2c_status s; |
networker | 0:371773dd3dd1 | 174 | for (int k=1; k< len; k++) data[k] = buffer[k-1]; |
networker | 0:371773dd3dd1 | 175 | do { |
networker | 0:371773dd3dd1 | 176 | s = _write(data, len, rpt);//toggle A and B, start with port |
networker | 0:371773dd3dd1 | 177 | } while (s == i2c_busy); |
networker | 0:371773dd3dd1 | 178 | delete[] data; |
networker | 0:371773dd3dd1 | 179 | } |