MCP23S17

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone,

 

I'm trying to use a MCP23S17 with my ATMEGA328P. I'm only trying to blink a LED, I checked the registers many time but I can not get the result I want. I was wondering if some of you have an idea of what is wrong. There is my code : 


//SPI
#define SPI_PORT     PORTB
#define SPI_DDR      DDRB
#define MOSI         3
#define SCK          5
#define CS           2

//MCP23S17 SPI SLAVE
#define SPI_ESCLAVE_ID    0x40
#define SPI_ESCLAVE_ADDR  0x00
#define SPI_ESCLAVE_WRITE 0x00
#define SPI_ESCLAVE_READ  0x01

//MCP2317 REGISTER
#define IODIRA  0x00
#define IODIRB  0x01
#define IOCONA  0x0A
#define GPPUA   0x0C
#define GPPUB   0x0d
#define GPIOA   0x12
#define GPIOB   0x13

void init_uc();
void SPI_Write(unsigned char addr,unsigned char data);

int main(){

init_uc();

while(1){

SPI_write(GPIOA,0xff);
_delay_ms(500);
SPI_write(GPI0A,0x00);
_delay_ms(500);

}

return 0;

void init_uc()
{

 //SPI

    // MOSI & SCK output,others as input
    SPI_DDR|=(1<<MOSI)|(1<<SCK)|(1<<CS);

    //ENABLE SPI, MASTER
    SPCR|=(1<<MSTR)|(1<<SPE);

    //INITIALISATION MCP23s17
    SPI_Write(IOCONA,0x28); // I/O CONTROL REGISTER : BANK = , SEQ0P=1, HAEN=1
    SPI_Write(IODIRA,0x00); //GPIOA as output
    SPI_Write(IODIRB,0xff); //GPIOB as input
    SPI_Write(GPPUB,0xff); //pull-up
    SPI_Write(GPIOA,0x00); // reset output GPIOA
}

void SPI_Write(unsigned char addr,unsigned char data)
{   

   //activate CS PINT
    SPI_PORT&=~(1<<CS);

    //start communication
    SPDR = SPI_ESCLAVE_ID |((SPI_ESCLAVE_ADDR<<1)&0x0E)|SPI_ESCLAVE_WRITE;

    //wait for transmission complete
    while(!(SPSR & (1<<SPIF)));

    //send data
    SPDR = data;

    //wait for transmission complete
    while(!(SPSR & (1<<SPIF)));

    //disable CS
    SPI_PORT|=(1<<CS);
}

Well, I have no error in the code and my LED only highlight.

 

Thank you for your future help.

 

EDIT : I forgot, I didnt  change it but esclave stands for slave

Last Edited: Thu. May 18, 2017 - 08:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code "looks" fine to me. 

 

From a personal point of view,  I would put spaces around operators and use = instead of |= whenever possible.    Always format the code nicely.   e.g. ctl-T in Arduino or ctl-K,ctl-D in AS7.

 

The first step is to make Spi_Write() return a value.    Void functions are the work of the Devil.

Then you write to a register and read it back.    This will verify that your chip is ok.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It looks like SPI_Write never uses the addr parameter. I think it should be used instead of SPI_ESCLAVE_ADDR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How have you connected A0-A2? They form part of the address.

 

The datasheet says "Hardware address pin. Must be externally biased" , if not connected the address can be all over the place.

 

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your answers. I have connected A0-A2 to the ground and I tried to use the addr parameter but it still does not work...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From the datasheet:

1.3.3 SPI INTERFACE
1.3.3.1 SPI Write Operation
The SPI write operation is started by lowering CS. The
Write command (slave address with R/W bit cleared) is
then clocked into the device. The opcode is followed by
an address and at least one data byte.
1.3.3.2 SPI Read Operation
The SPI read operation is started by lowering CS. The
SPI read command (slave address with R/W bit set) is
then clocked into the device. The opcode is followed by
an address, with at least one data byte being clocked
out of the device.
1.3.3.3 SPI Sequential Write/Read
For sequential operations, instead of deselecting the
device by raising CS, the master clocks the next byte
pointed to by the Address Pointer. (see Section 1.3.1
“Byte Mode and Sequential Mode” for details
regarding sequential operation control).
The sequence ends by the raising of CS.
The MCP23S17 Address Pointer will roll over to
address zero after reaching the last register address.

So you should do :

uint8_t MCP23S017(uint8_t SLAVE, uint8_t addr, uint8_t val)
{
    CS_low();
    spi(SLAVE);      //match the A0-A2 pins
    spi(addr);       //select operation
    ret = spi(val);  //write/read result
    CS_high();
    return ret;
}

Untested.   No,  I can't see why you have a SLAVE address on an SPI device.   Surely that is what the CS (Chip-Select) does.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Untested. No, I can't see why you have a SLAVE address on an SPI device. Surely that is what the CS (Chip-Select) does.

 

my guess is it is because there is also an i2c version of this chip& it makes the internals easier (probably the same die for both with just the relevant connections made to the outside world)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, thank you everyone it is now fixed. I did forget to add the addr parameter but when I added it I forgot to wait for the end of the transmission. 

 

Thank you again.