|
|
View previous topic :: View next topic |
Author |
Message |
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
Help w/ MCP23S17, SPI Port Expander |
Posted: Sun Apr 23, 2006 4:23 pm |
|
|
Hello All,
I’m having a hard time getting a SPI port expander working 100%. I’m using a MCP23S17 connected to the hardware SPI on a 18F4620. (The pertinent code is below.) I can reliably poll the switches, but the output to the LEDs just doesn’t want to work 100% of the time. Right now I just use them as ‘heartbeat’ to give visual indication that the PIC is running.
Symptoms:
Upon cycling power the LEDs may or may not flash, but everything else is working great. RS232 output works, PIC polls MCP23S17 and receives reliable and accurate info on PORTA switches. Unfortunately I can’t produce any repetitive results to narrow done the problem.
I have tried:
Replacing LDO
Replacing MCP23S17
Up to 10uF cap at MCP23S17
One thing I’m unsure of is the difference between the GPIOB register and the OLATB register. Do they both need to be set high for the output to be reliably high? My experiments have shown that either can be set high to get things working.. sometimes.
MCP23S17 Connections:
GPA0 P/U w/ 10K to 5V (RTC alarm active low)
GPA1 P/U w/ 10K to 5V (MOM Sw to Gnd)
GPA2 P/U w/ 10K to 5V (MOM Sw to Gnd)
GPA3 P/U w/ 10K to 5V (MOM Sw to Gnd)
GPA4 P/U w/ 10K to 5V (MOM Sw to Gnd)
GPA5 P/U w/ 10K to 5V (MOM Sw to Gnd)
GPA6 Unconnected
GPA7 Unconnected
GPB0 P/U w/ 10K to 5V (not connected otherwise)
GPB1 P/U w/ 10K to 5V (not connected otherwise)
GPB2 P/U w/ 10K to 5V (not connected otherwise)
GPB3 P/U w/ 10K to 5V (not connected otherwise)
GPB4 to LED then 470R then Gnd
GPB5 to LED then 470R then Gnd
GPB6 to LED then 470R then Gnd
GPB7 Unconnected
This is the stuff that's in the header:
Code: | //The following are for address 000, i.e. A2,A1,A0 = 0.
#define write_byte 0b01000000
#define read_byte 0b01000001
//The following are the Power-Up values for the control registers, they will
//be application specific. They are presented in the Bank 0 format,
//alternating between PORTA and PORTB.
//Port direction, 1 = input, 0 = output
#define IODIRA_PU 0b00111111
#define IODIRB_PU 0b00001111
|
These two functions are in the MAIN() prior to the WHILE(TRUE):
Code: | /*
Put EXT_IO chip in default power-up state
*/
void reset_ext_io(void) {
output_low(EXT_IO_RESET);
delay_us(5); //pulse reset pin low
output_high(EXT_IO_RESET); //bring reset pin high
delay_us(5); //allow time to settle before continuing
}
/*
Put EXT_IO chip in user desired power-up state
NOTE: Only use after reset_ext_io(), and add any values to write_spi() that are
different from default POR values.
*/
void setup_ext_io(void) {
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16); //use middle of the road clock speed, part is good to 10mHz
output_low(EXT_IO_CS); //select ext_io chip
delay_us(5); //allow everything to catch-up
spi_write(write_byte); //send write op_code
spi_write(0x00); //send starting address for config
spi_write(IODIRA_PU);
spi_write(IODIRB_PU);
output_high(EXT_IO_CS); //de-select ext_io chip
delay_us(5); //allow everything to catch-up
}
|
Any help would be greatly appreciated.
Thanks,
John |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Mon Apr 24, 2006 4:29 pm |
|
|
SOLVED.
Removed a
statement prior to resetting and configuring and everything works now.
Go figure. |
|
|
zcbm2724 Guest
|
MCP23S17 |
Posted: Sun Dec 31, 2006 5:07 pm |
|
|
Hi.
Did not get correlation between the code, and what u did to it.
I am in the similar problem situation
Can you put the significant part (non proprietary) of code to initialize and interface SP including, configuring the registers.
Appreciate your help.
regards |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1908
|
|
Posted: Sun Dec 31, 2006 6:17 pm |
|
|
I also use a pair of MCP23S17's in a project, but I don't use the processor's MSSP module to communicate. I instead bit-bang everything. This is with a 18F2480. One IO expander has its address lines all pulled low, the other has them all pulled high. Code is below. Simply call io_init() to initialize the IO expanders. I use each in output mode only.
Code: | #define IO_CS PIN_C0
#define IO_RESET PIN_C1
#define SPI_CLK PIN_A4
#define SPI_DOUT PIN_A3
#define SPI_DIN PIN_A2
#define WRITE 0
#define READ 1
#define BANK1 0x80
#define DISABLE_SLEW 0x10
#define ENABLE_HW 0x08
#define IO_1 0x0e
#define IO_2 0x00
#define CONTROL_REG 0x0a
#define DIRECTION_REG 0x00
#define A_BANK 0
#define B_BANK 0x10
#define LATCH_REG 0x0a
int8 control_byte = 0x40;
void io_init(void) {
int8 readback;
output_high(IO_CS);
output_high(SPI_CLK);
delay_us(100);
output_low(IO_RESET); // hard reset
delay_us(50);
output_high(IO_RESET);
delay_ms(10);
// now must set up the io expanders
write_io(control_byte|IO_1|WRITE, CONTROL_REG, BANK1|ENABLE_HW|DISABLE_SLEW); // sets up IO 1
write_io(control_byte|IO_2|WRITE, CONTROL_REG, BANK1|ENABLE_HW|DISABLE_SLEW); // sets up IO 2
// now must first write 0's into their output latches, then change port directions to output
write_io(control_byte|IO_1|WRITE, LATCH_REG|A_BANK, 0);
write_io(control_byte|IO_1|WRITE, DIRECTION_REG|A_BANK, 0);
write_io(control_byte|IO_1|WRITE, LATCH_REG|B_BANK, 0);
write_io(control_byte|IO_1|WRITE, DIRECTION_REG|B_BANK, 0);
write_io(control_byte|IO_2|WRITE, LATCH_REG|A_BANK, 0);
write_io(control_byte|IO_2|WRITE, DIRECTION_REG|A_BANK, 0);
write_io(control_byte|IO_2|WRITE, LATCH_REG|B_BANK, 0);
write_io(control_byte|IO_2|WRITE, DIRECTION_REG|B_BANK, 0);
}
void write_io_byte(int8 data) {
int8 i;
delay_us(20);
for (i = 0; i < 8; i++) {
output_low(SPI_CLK);
if (bit_test(data, 7 - i)) {
output_high(SPI_DIN);
}
else {
output_low(SPI_DIN);
}
delay_us(6);
output_high(SPI_CLK);
delay_us(6);
}
}
void write_io(int8 control, int8 address, int8 data) {
delay_us(20);
output_high(SPI_CLK);
output_high(SPI_DIN);
delay_us(20);
output_low(IO_CS);
write_io_byte(control);
write_io_byte(address);
write_io_byte(data);
delay_us(20);
output_high(IO_CS);
}
int8 read_io(int8 control, int8 address) {
int8 register_state = 0;
int8 i;
delay_us(20);
output_high(SPI_CLK);
output_high(SPI_DIN);
delay_us(20);
output_low(IO_CS);
write_io_byte(control);
write_io_byte(address);
for (i = 0; i < 8; i++) {
register_state = register_state << 1;
output_low(SPI_CLK);
delay_us(6);
if (input(SPI_DOUT)) {
register_state = register_state | 0x01;
}
output_high(SPI_CLK);
delay_us(6);
}
delay_us(20);
output_high(IO_CS);
return(register_state);
} |
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|