News:

Let's find out together what makes a PIC Tick!

Main Menu

PCA9535 I/O Texas Instruments

Started by Peter Truman, Jun 17, 2023, 05:43 AM

Previous topic - Next topic

Peter Truman

Hi

I'm having trouble getting control of this TI I/O expander I/O Expander

I have it wired up as per the schematic attached.

My problem is (apart from being a bit dense) - the datasheet is not as clear as it could be.

My initial aim is to toggle Rly 1 on port 0 bit 0

The device slave address in this configuration is %00100000 (Decimal 32)

Symbol I/O = 32

In order to do that I have to set the configuration registers

The datasheet seems to suggest I can configure each register in turn with one busout command?
so Busout 32,[4,255,255,0,255] - start at register 4 (Polarity port 0 invert - default is all 1s), followed in turn by Polarity invert port 1, Config reg port 0 and config reg port 1) to make port 0 all outputs and port 1 all inputs

After that I should be able to write to each output pin on port 0 by sending a byte sized bit pattern to reg 2 (Output port 0) So my test code looks like this (after setting up the I2C in the usual way)

BusOut IO,[4,255,255,0,255]                               'configure the IO



test:
    @Clrwdt
    HRSOut2 "On",13
    BusOut IO,[2,255]           'all on
    DelayMS 1000
    BusOut IO,[2,0]     'all off
    HRSOut2 "Off",13
    DelayMS 1000
GoTo test

That didn't work - but didn't hang either

So I tried like this in an attempt to simply things and just write to the port a config register

BusOut IO,[6,0]     'config register 6 as all outputs


test:
    @Clrwdt
    HRSOut2 "On",13
    BusOut IO,[2,255]           'all on
    DelayMS 1000
    BusOut IO,[2,0]     'all off
    HRSOut2 "Off",13
    DelayMS 1000
GoTo test


Nothing seems to work

Does anyone have any experience with this chip?

RGV250

Hi,
Try using 64 as the address, if you look on page 21 of the datasheet in your link the address is bits1 to 7 and bit 0 is the read/write bit.

Bob

Peter Truman

Well Bob - tried that and it works a treat!

You are a steely eyed rocket guy - as they say.

Now all I need to do is figure out how I should read these datasheets - see the attachment. So I understand the last bit of the slave is used to indicate a read or write. I had assumed (wrongly - obviously) thatif the datasheet specified the address as 32 - then it would be 32!

Anyway - working now - so thanks for your help, much appreciated

RGV250

#3
Hi,
I think if you have IO_Read = 65 and IO_Write = 64 that should work.
As for the attachment, that is just if you have more devices on the bus or decide to use a different address. If you had A0 High (33) it would be 66 / 67 for read & write. Basically shift the address 1 to the left and add 1 or not depending on read/write. I get caught out a lot with that, I believe Arduino and possibly others do it automatically but there must be a good reason for not doing it or Les would have implemented it.

Bob

John Lawton

Arduino may make it work but do you really learn what's going on 'under the bonnet/hood' that way?
To me Positron has a great balance of hiding some detail but also not doing too much for you, so you, the programmer, are always in control.

AlbertoFS

Hi all,
I just finished a library for the PCA9535 expander in Interrupt Mode. It hasn't been easy because the expander doesn't have an interrupt register. Another expander with double interrupts is a curse...
I keep testing and tomorrow I'm going to publish this library.
Regards
73's de EA3AGV

tumbleweed

QuoteI just finished a library for the PCA9535 expander in Interrupt Mode
Isn't it really dangerous to use an I2C device in an ISR?

Since I2C transactions can't be interrupted by another I2C transaction, I find it's usually more trouble than it's worth unless you don't use I2C in the main program.

The only way to make it reliable is to disable I2C interrupt processing whenever you want to use it.

Peter Truman

It turns out I needed to add an 'ad hoc' update to the I/O in some circumstances - I couldn't flag it in the interrupt and deal with it in the main loop because it had to be more precise than that. So, I just put in the interrupt and disabled further interrupts around it. Not ideal but it does work.

AlbertoFS

#8
Hi all,
Maybe there is a confusion to use the interrupt with expanders.
I never write code in an ISR. I use a flag that I resolve in the main program.
Expanders are not for reading fast signals, on the contrary. With your double interrupt problem, the second read might override the first. With any mechanical contact you have to place a delay to be out of the rebound zone. I write an average delay of 35 mS.
Also that helps in solving the double interrupt problem.

So in my libraries I use a delay of 35mS that I can take up to 100mS after the interruption, the maximum delay to read a push button. To such an extent that the ISR response could be placed in the "Low Interrupt" section and there would be no major problem.

However the PCA9535 expander does not have an interrupt register that would give the input information. Port information could be lost.
If you are concerned about speed, you could use the MCP23S17 with SPI and interrupt register. But, you would also have to use a delay to avoid bouncing!

If the programmer cannot service an interrupt after 100mS, the problem is not with the expander.

In my libraries I always write all the necessary commands so that the user can use all the possible functions, the interrogation mode as well.
Thank you
73's de EA3AGV

Peter Truman

Agreed, in my case I'm quite happy to use the Interrupt to service inputs, but I needed to change the status of an output more quickly than the average 100ms cycle time of my polling output.

So I was counting up tmr interrupts and setting a flag every 100ms. I would service this flag in my main routine to update my outputs. I only needed to do an ad hoc change every now and then. Thinking about it now, I would force the flag and update the expander that way.

AlbertoFS

Hi Peter,

When a sensor changes state, an interrupt is generated and your code would have up to 30 mS (more or less) to attend to this interrupt. (there is another 35mS delay for debounces) Once the expander has been read, it has plenty of time to generate a response.

When the sensor returns to its initial position, the expander generates another interrupt that the library procedure pushes away.

Could you tell me how your sensors are connected so that I can modify the ISIS schematic and verify that everything will go well for your proyect?

Regards
73's de EA3AGV

Peter Truman

The inputs are not really an issue - but I have a piezzo buzzer connected via one of the I/O ports.

I have a variety of 'beeps' generated according to particular activities. For example, a user entering a menu gets a 100ms beep, changing between menus gets you a 50ms beep and selecting between various numbers gets you a 1ms beep.

I have a 1ms timebase in an interrupt so when I want a 100ms beep I set a variable to 100 and turn the beeper on, then every iteration of the interrupt decrements the counter by 1, as soon as it reaches 0 I turn off the piezzo.

Generally this is fine when I update the I/O every 100ms but obviously, anything less, and especially 1 ms beeps, I can't afford to wait.

I have learned that next time I design a board I'll drive the peizzo direct from the pic 🤔

Thanks for the help, I appreciate it

AlbertoFS

Hi Peter,
I wish you the best for your project.
In the past, I have had noise problems when connecting a piezo buzzer to a PIC output. One solution has been to place an NPN transistor to drive the buzzer. And connecting the +V of the buzzer directly to the output of the regulator.
Regards
73's de EA3AGV