/******************************************************************************
* MCP23017_Test *
* *
* Mike McLaren, K8LH *
* Micro Application Consultants *
* *
* MCP23017 I2C driver experiment *
* *
* *
* *
* 05-Jan-2021 Arduino 1.8.13 / Arduino Nano *
******************************************************************************/
//#include <Wire.h> // switched to 'direct register'
/******************************************************************************
* function prototypes *
******************************************************************************/
/******************************************************************************
* hardware constants, helper macros, variables *
******************************************************************************/
#define mcpAddr 0x20<<1 // MCP23017 I2C address shifted left 1 bit
#define IODIRA 0x00 // MCP23017 register locations (BANK = 0)
#define IODIRB 0x01
#define POLA 0x02
#define POLB 0x03
#define INTENA 0x04
#define INTENB 0x05
#define DEFVALA 0x06
#define DEFVALB 0x07
#define INTCONA 0x08
#define INTCONB 0x09
#define IOCON 0x0A
#define IOCON2 0x0B
#define GPPUA 0x0C
#define GPPUB 0x0D
#define INTFA 0x0E
#define INTFB 0x0F
#define INTCAPA 0x10
#define INTCAPB 0x11
#define GPIOA 0x12
#define GPIOB 0x13
#define IOLATA 0x14
#define IOLATB 0x15
#define hiNibble(x) ((x >> 4) & 0x0F)
#define loNibble(x) ((x >> 0) & 0x0F)
const char hex[] = "0123456789ABCDEF";
/******************************************************************************
* low level UART functions *
******************************************************************************/
#define RX_READY (UCSR0A & 1<<RXC0) //
#define TX_READY (UCSR0A & 1<<UDRE0) //
void put232(uint8_t data) // ************************************
{ while(!TX_READY); UDR0 = data; // send byte or character *
} // ************************************
void putStr(char *data) // ************************************
{ while(*data) put232(*data++); // send string variable *
} // ************************************
/* *
* overload function for FlashStringHelper string constants *
* */
void putStr(const __FlashStringHelper *ifsh)
{ PGM_P p = reinterpret_cast<PGM_P>(ifsh);
while(char c = pgm_read_byte(p++))
put232(c);
} //
uint8_t rxAvail(void) // ************************************
{ if(RX_READY) // *
return 1; // *
else // *
return 0; // *
} // ************************************
uint8_t get232(void) // ************************************
{ return (uint8_t) UDR0; // *
} // ************************************
void putHex(byte work) // ************************************
{ put232(hex[hiNibble(work)]); // *
put232(hex[loNibble(work)]); // *
} // ************************************
/******************************************************************************
* low level I2C functions *
******************************************************************************/
#define TW_START 0xA4 // (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
#define TW_READY (TWCR & 0x80) // ready when TWINT returns to logic 1
#define TW_STATUS (TWSR & 0xF8) // returns value of status register
#define TW_SEND 0x84 // (1<<TWINT)|(1<<TWEN)
#define TW_STOP 0x94 // (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
#define TW_ACK 0xC4 //
#define TW_NAK 0x84 //
#define I2C_Stop() TWCR = TW_STOP // macro
void I2C_Init() // ************************************
{ TWSR = 0; TWBR = 72; // prescaler 1, 100-kHz clock *
} // ************************************
byte I2C_Start() // ************************************
{ TWCR = TW_START; while(!TW_READY); // send start condition & wait *
return(TW_STATUS == 0x08); // 1 if found, 0 otherwise *
} // ************************************
byte I2C_SendAddr(byte addr) // ************************************
{ TWDR = addr; // load device's I2C bus address *
TWCR = TW_SEND; while(!TW_READY); // send it & wait *
return(TW_STATUS == 0x18); // 1 if found, 0 otherwise *
} // ************************************
byte I2C_Write(byte data) // ************************************
{ TWDR = data; // send data byte to slave *
TWCR = TW_SEND; while(!TW_READY); // send it & wait *
return(TW_STATUS != 0x28); // *
} // ************************************
byte I2C_ReadNAK() // ************************************
{ TWCR = TW_NAK; while(!TW_READY); // *
return TWDR; // *
} // ************************************
/******************************************************************************
* *
******************************************************************************/
void writeReg(byte reg, byte value) // ************************************
{ I2C_Start(); // *
I2C_SendAddr(mcpAddr); // *
I2C_Write(reg); // *
I2C_Write(value); // *
I2C_Stop(); // *
} // ************************************
void writeReg(byte reg, byte valA, byte valB) // ****************************
{ I2C_Start(); // *
I2C_SendAddr(mcpAddr); // *
I2C_Write(reg); // *
I2C_Write(valA); // *
I2C_Write(valB); // *
I2C_Stop(); // *
} // ************************************
byte readReg(byte reg) // ************************************
{ byte value = 0; // *
I2C_Start(); // *
I2C_SendAddr(mcpAddr); // *
I2C_Write(reg); // *
I2C_Start(); // restart *
I2C_SendAddr(mcpAddr+1); // read command *
value = I2C_ReadNAK(); // *
I2C_Stop(); // *
return value; // *
} // ************************************
/* void writeReg(uint8_t reg, uint8_t value)
{ Wire.beginTransmission(mcpAddr); //
Wire.write(reg); //
Wire.write(value); //
Wire.endTransmission(); //
} //
void writeReg(uint8_t reg, uint8_t portA, uint8_t portB)
{ Wire.beginTransmission(mcpAddr); //
Wire.write(reg); //
Wire.write(portA); //
Wire.write(portB); //
Wire.endTransmission(); //
} //
/******************************************************************************
* *
******************************************************************************/
#define _BAUD (115200/2) // 57600 or 115200 (double speed)
#define _UBRR (F_CPU/16)/_BAUD-1 // Used for UBRRL and UBRRH
int main() // ************************************
{ DDRD |= 0b00000010; // *
DDRC |= 0b00100000; // PB4(SDA) input, PB5(SCL) output *
PORTC |= 0b00110000; // pull-ups *
DDRB |= 0x01; // mclr Output *
// *
UBRR0 = _UBRR; // setup USART *
UCSR0A |= _BV(U2X0); // " (57600 x 2 for 115200 baud) *
UCSR0B |= _BV(TXEN0); // " *
UCSR0B |= _BV(RXEN0); // " *
UCSR0C = 3<<UCSZ00; // async' 8/N/1 *
put232('\n'); // *
putStr(F(" PIC MCP23017 Test\n")); // *
putStr(F(" Mike McLaren, K8LH \n")); // *
// *
//Wire.begin(); // *
//Wire.setClock(400000); // 400-kHz *
I2C_Init(); // *
writeReg(IOCON,0b00100000); // sequential off *
writeReg(IODIRA,0x00); // port A outputs *
writeReg(IODIRB,0x00); // port B outputs *
writeReg(IOLATA,0b00000000); // port A latches *
writeReg(IOLATB,0xAA); // port B latches *
byte x = 0;
while(1) // **** loop **************************
{ if(rxAvail()) // get serial working first *
put232(get232()); // ok, got it... *
writeReg(IOLATA, x, x); // test MCP23017 outputs *
_delay_ms(50); x++; // ok, it works *
} // ************************************
}