Troubleshooting MCP23S17 and the(?) solution.

Post Reply
rasmadrak
Posts: 218
Joined: Mon Aug 15, 2011 9:21 pm
Location: Sweden
Contact:

Troubleshooting MCP23S17 and the(?) solution.

Post by rasmadrak » Fri Jul 21, 2017 9:57 am

So, long story short - I've designed a PCB, manufactured it and soldered on components. At the core there's a Chipkit Max32 and a bunch of other stuff, including four MCP23S17. Since there's limited information about MCP's interaction in code on the web, at least easily graspable without digging too much.

The problem was that the MCP's simply wouldn't work correctly and I tried three different libraries - what ended working for me was a modified version of Majenko's library. In that library's read and write functions, only a single data transfer was made per SPI session (in addition to cmd and opcode etc). To the best of my knowledge, that should work as the transaction is finalized when slaveselect is pulled high. The other libraries I didn't get to work at all. The MCP's are using the same DSPI port, with individual slave selects and individual hardware addresses as well, and the design of the circuit is by the books.

But.
When doing full port writes and/or several consecutive writes/read, the MCP's would fail and date would be garbled, ending up on the wrong pins and simply not working and lighting up pins despite sending all zeroes etc. Single pin writes would mostly work, which led me to do hardware "voodoo" and I was tempted to bring out the soldering iron and order new parts etc. Sometimes the order of the commands would make a huge difference in function; It could work, and after a recompile it failed to run etc, typical non-initialized variable problems - except in hardware.

But - Part 2.
I dug into the specs, double checked everything and found that the solution was simple enough - by always talking to the first port, using BANK=0 (paired A-B ports), and writing both A and B during the same SPI "session", the problem vanished completely. Now I can write (haven't tried reading) and the correct pins would be activated at all times. I can run full 10MHz without a glitch inside and outside an interrupt/core service.

Example change:

Code: Select all

//FROM:
void MCP23S17::readRegister(uint8_t addr) {
    if (addr > 21) return;
    	
    select();
    _spi->transfer(0b01000001 | ((_addr & 0b111) << 1));
    _spi->transfer(addr);
    _reg[addr] = _spi->transfer(0xFF);
    deselect();
}

//TO:
void MCP23S17::readRegister(uint8_t addr) {
    if (addr > 21) return;
    	
    select();
    _spi->transfer(0b01000001 | ((_addr & 0b111) << 1));
    _spi->transfer(addr);
    _reg[addr] = _spi->transfer(0xFF);
    _reg[addr+1] = _spi->transfer(0xFF);    
    deselect();
}

//USAGE:
//Instead of doing :
readRegister(GPIOA);
readRegister(GPIOB);

//I now do:
readRegister(GPIOA);
    
Majenko is a great coder, and the library itself is indeed very neat - so I highly doubt this error would have sneaked passed him, and I'm wondering if this is due to a hardware revision in the MCP's, or DSPI / SPI differences or perhaps something else? The fact that none of the other libraries worked for me is also weird. It just doesn't add up to me, but I think this section of the specs' might be the issue:
3.2.1 BYTE MODE AND SEQUENTIAL MODE
The MCP23X17 family has the ability to operate in Byte mode or Sequential mode (IOCON.SEQOP).

IOCON, Bit 5;
1 = Sequential operation disabled, address pointer does not increment.
0 = Sequential operation enabled, address pointer increments.

Byte mode disables automatic Address Pointer incrementing. When operating in Byte mode, the MCP23X17 family does not increment its internal address counter after each byte during the data transfer. This gives the ability to continually access the same address by providing extra clocks (without additional control bytes). This is useful for polling the GPIO register for data changes or for continually writing to the output latches.

A special mode (Byte mode with IOCON.BANK = 0) causes the address pointer to toggle between associated A/B register pairs.For example, if the BANK bit is cleared and the Address Pointer is initially set to address 12h (GPIOA) or 13h (GPIOB), the pointer will toggle between GPIOA and GPIOB. Note that the Address Pointer can initially point to either address in the register pair.
Sequential mode enables automatic address pointer incrementing. When operating in Sequential mode, the MCP23X17 family increments its address counter after each byte during the data transfer. The Address Pointer automatically rolls over to address 00h after accessing the last register.

These two modes are not to be confused with single writes/reads and continuous writes/reads that are serial protocol sequences. For example, the device may be configured for Byte mode and the master may perform a continuous read. In this case, the MCP23X17 would not increment the Address Pointer and would repeatedly drive data from the same location.
Majenko's library default to use BANK=0, HAEN=1, SEQOP=1, unless I'm mistaken, so the problem might be the special mode and that the chip expects the next port to be read immediately after?

Anyhow - Hopefully this helps someone else who's wrestling with these IC's in the future! :ugeek:

rasmadrak
Posts: 218
Joined: Mon Aug 15, 2011 9:21 pm
Location: Sweden
Contact:

Re: Troubleshooting MCP23S17 and the(?) solution.

Post by rasmadrak » Mon Jul 24, 2017 4:05 pm

Update:
Reading doesn't work, it always returns 0xFFFF or 0x0000.
I've also tried manually talking to the MCP's with SPI commands and it seems that HAEN never gets enabled.
However, my setup is a bit peculiar though;

All four chips has their own CS line and unique HW address, but utilize the same SPI channel.
Could this be the issue, even if I init each chip?
Will investigate further.

User avatar
majenko
Site Admin
Posts: 2165
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: Troubleshooting MCP23S17 and the(?) solution.

Post by majenko » Mon Jul 24, 2017 5:04 pm

If they have a unique CS pin they have no need of a unique hardware address. The hardware address only makes any sense when you have multiple chips on a single CS pins, as in my 32-port IO expander.
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

rasmadrak
Posts: 218
Joined: Mon Aug 15, 2011 9:21 pm
Location: Sweden
Contact:

Re: Troubleshooting MCP23S17 and the(?) solution.

Post by rasmadrak » Mon Jul 31, 2017 12:34 am

majenko wrote:If they have a unique CS pin they have no need of a unique hardware address. The hardware address only makes any sense when you have multiple chips on a single CS pins, as in my 32-port IO expander.
Yes, and that was the plan as well. But then I thought while designing the PCB, "I'll put the HW addresses in there, just in case". :)
I don't know if that messed things up, but to be honest I haven't had the time to investigate further. I'll try to get ultra basic once that is done, could possibly be something else that is interfering with the SPI port/pins.

Post Reply