PDA

View Full Version : Word Variable and I2C



Scampy
- 19th May 2014, 22:29
Hi,

I had a system that used a byte variable to store the PWM value to fade up and down some leds. It worked well, but having 0-255 the resolution was very noticeable, especially at low values. I now have a chip that communicates over I2C and can drive 12 PWM outputs with a resolution of 4096 steps. The problem is that with a word variable in a similar situation is 0 - 65335 and the device ignores the first 4 bits according to the datasheet ( http://www.nxp.com/documents/data_sheet/PCA9685.pdf )

Can anyone advise how I can get the resolution to cover the 12bit word range and write this to the chip. I've tried


I2CWRITE SDApin,SCLpin,i2cWriteAddress,i2cControl,[0,0,pcaPwmValue.highbyte,pcaPwmValue.lowbyte >> 8]


But that doesn't work.

HenrikOlsson
- 20th May 2014, 06:28
Hi,
The likely reason for it not to work the way you have it is because you take the low byte of the word variable and shift it 8 bits to the right, "pushing" the actual value out. Just remove the >> 8 part of it and see if it works.

On the other hand, the manual says:

If a word- or long-sized Value is specified, the bytes are sent highest byte first,
followed by the lower byte(s).
Which is exactly what you're trying to do so you could simply specify the word size variable, no highbyte/lowbyte stuff needed if I understand correctly.

/Henrik.

EarlyBird2
- 20th May 2014, 06:43
Although the registers are described as 12 bit they do have 8 bit and 4 bit portions that are accessible separately.

7.3.3 LED output and PWM control
The turn-on time of each LED driver output and the duty cycle of PWM can be controlled
independently using the LEDn_ON and LEDn_OFF registers.
There will be two 12-bit registers per LED output. These registers will be programmed by
the user. Both registers will hold a value from 0 to 4095. One 12-bit register will hold a
value for the ON time and the other 12-bit register will hold the value for the OFF time. The
ON and OFF times are compared with the value of a 12-bit counter that will be running
continuously from 0000h to 0FFFh (0 to 4095 decimal).
Update on ACK requires all 4 PWM channel registers to be loaded before outputs will
change on the last ACK

Example 1: (assumes that the LED0 output is used and
(delay time) + (PWM duty cycle) ≤ 100 %)
Delay time = 10 %; PWM duty cycle = 20 % (LED on time = 20 %; LED off time = 80 %).
Delay time = 10 % = 409.6 ~ 410 counts = 19Ah.
Since the counter starts at 0 and ends at 4095, we will subtract 1, so delay time = 199h
counts.
LED0_ON_H = 1h; LED0_ON_L = 99h
LED on time = 20 % = 819.2 ~ 819 counts.
Off time = 4CCh (decimal 410 + 819 − 1 = 1228)
LED0_OFF_H = 4h; LED0_OFF_L = CCh

I read this to mean that you need four i2c write statements
led0_on_h = 1h
led0_on_l =99h
led0_off_h = 4h
led0_off_l =cch

but maybe the registers will auto increment and only one i2c write statement is required.

I could be wrong and I have no way to test my interpretation.

Scampy
- 20th May 2014, 11:41
many thanks for the comments, a lot of which went over my head :)

After I posted I re-read the data sheet again and noted that you can define the "start" position and the "end" position of each post. I therefore tried the following, which again didn't work
I2CWRITE SDApin,SCLpin,i2cWriteAddress,i2cControl,[0,0,1,pcaPwmValue >> 8]

I've also tried the highbyte / lowbyte option, but again that didn't work, with the values jumping up in tens *ie 4050, 4060, after it passed 255.

there is an auto increment option, but I'm not sure if this runs but default or needs setting using a register.

Scampy
- 20th May 2014, 13:19
Hi,
Just remove the >> 8 part of it and see if it works.


/Henrik.

Henrik,

I just tried that with the the following:


pcaChannel = 0 ;Set a PWM channel
pcaPwmValue = B_PWM ;Send current value
lcdout $FE,$D4+0,"PWM ",dec pcaPwmValue
i2cControl = $6 + 4*pcaChannel ;LED0_ON_L $6
I2CWRITE SDApin,SCLpin,i2cWriteAddress,i2cControl,[0,0,1,pcaPwmValue]


I've run a test and that seems to work in as far as the LED on channel 0 fades up. What I did notice though was that the LCD continued to count up past 4095. Notice I placed a 1 as the value for the "ON" setting following Steve's comments. I'm hoping that is correct ?

I'm re-running the test as I missed the point where the LED on channel one went off. I'm hoping that it was when the value was close or exactly 4095, as at least that would prove the range that is being accepted. Just need to figure out how to specify the size of the variable as you suggest - any pointers ?

HenrikOlsson
- 20th May 2014, 14:00
Hi,

I've run a test and that seems to work in as far as the LED on channel 0 fades up. What I did notice though was that the LCD continued to count up past 4095. Notice I placed a 1 as the value for the "ON" setting following Steve's comments. I'm hoping that is correct ?
I don't know, I haven't read the datasheet for the device you're using, I only commented on the use of I2CWRITE from a general perspective.


Just need to figure out how to specify the size of the variable as you suggest - any pointers ?
Not sure I understand... I've never used I2C but I'm pretty sure that, unlike SHIFTOUT, the transactions are always in bytes. In other words all transactions are in multiple of 8bits. If the device you're talking to is actually USING 1 or 7 or 12 or 14 bits out of the 8 or 16 you send is completely up to that device. However, if the device specify a range from 0 to 4095 then actually SENDING it value outside that range would/could result in unexpected things. Again, I haven't read the datasheet for the device in question.

As the documentation for I2CWRITE says, specifying a BYTE variable will send a byte variable, specifying a WORD variable will send a WORD variable (two bytes, high byte first).

If you want to prevent the value you're sending from ever going above 4095 you can, for example, AND it with 4095.

/Henrik.

Scampy
- 20th May 2014, 15:12
Henrik, thanks again for the reply.

Using the code in my last post (#5) the LED on channel 1 of the PCA chip fades up, all the way until pcaPwmValue reached 4096. At 4097 it went off, and as it increased (now at 6745) the LED on channel 1 has lit up but not on full brightness. What I can't understand is I have a B_MAX variable which has a value of 4095, with an "If B_PWM=B_MAX then doe something else statement which seems to be ignored. I was reading up on the variable statement and the manual comments that there is a size statement, with the use of additional modifiers, but I couldn't find any decent examples. Is there a way of simply limiting the word to 4095 something like B_PWM VAR Word size 4095 ??

HenrikOlsson
- 20th May 2014, 19:53
Hi,

Is there a way of simply limiting the word to 4095 something like B_PWM VAR Word size 4095 ??
Two ways that I can Think of right now, your way which you've somehow implemented wrong and the way I tried to explain in my previous post.



IF pcaPwmValue >= 4095 THEN pcaPwmValue = 4095 ' Clamp value at 4095
LCDOUT $FE,$D4+0,"PWM ",dec pcaPwmValue

Or....



pcaPwmValue = (B_PWM & 4095) ' Roll over value at 4095
LCDOUT $FE,$D4+0,"PWM ",dec pcaPwmValue

By your explaination it sounds as if the PCA chip is basically doing what the second approach above does, ie start over at 4096 and again at 8192 and again 12288 and so on.

/Henrik.

EarlyBird2
- 21st May 2014, 08:45
Henrik,

I just tried that with the the following:


pcaChannel = 0 ;Set a PWM channel
pcaPwmValue = B_PWM ;Send current value
lcdout $FE,$D4+0,"PWM ",dec pcaPwmValue
i2cControl = $6 + 4*pcaChannel ;LED0_ON_L $6
I2CWRITE SDApin,SCLpin,i2cWriteAddress,i2cControl,[0,0,1,pcaPwmValue]


I've run a test and that seems to work in as far as the LED on channel 0 fades up. What I did notice though was that the LCD continued to count up past 4095. Notice I placed a 1 as the value for the "ON" setting following Steve's comments. I'm hoping that is correct ?

I'm re-running the test as I missed the point where the LED on channel one went off. I'm hoping that it was when the value was close or exactly 4095, as at least that would prove the range that is being accepted. Just need to figure out how to specify the size of the variable as you suggest - any pointers ?

You are missing some of the detail contained in the user manual.

If you have not set Auto Increment on your i2cwrite is sending 0 then 0 then 1 then pcaPwmValue to $6.
To test this change your code to

I2CWRITE SDApin,SCLpin,i2cWriteAddress,i2cControl,[pcaPwmValue]

If I am correct in my interpretation it is also possible that you are only changing the first 8 bits as the 4 upper bits are address $7.