PDA

View Full Version : Troubles with I2C_Write



The Altruist
- 22nd March 2010, 02:56
I'm trying to send an I2C message to a non-EEPROM. Now everyone may laugh and say "So what's the problem?"
Every I2C example I've seen written is for EEPROMs. The I2C_WRITE command seems built around them.

The complicating part is the EEPROM address BYTE. That may seem odd, but I have a good reason. I'm not sending an address byte. I'm just sending pure data. In this case, I'm sending it to an I2C-driven DAC.

Right now, I'm using this method and nothing is working.

'Assuming 'result' is a word variable containing a 10-BIT value shifted left twice with 4 bits of empty header (per the DAC datasheet):
'So it looks like 0000xxxx-xxxxxx00

I2CWRITE PORTB.1, PORTB.4, $9C, result.HIGHBYTE, [result.LOWBYTE]

I'm using PBP 2.5, an ICD2, a PIC16F819, and a DAC101C085.

Any suggestions?

mackrackit
- 22nd March 2010, 04:17
Here is an example with a RTC
http://www.picbasic.co.uk/forum/showthread.php?t=12671

But the problem might be with the placement of the [ ]

Showing your whole code may also help. Where is the data coming from?

Darrel Taylor
- 22nd March 2010, 04:25
In the manual, there are small clues that take some getting used to.

I2CWRITE DataPin,ClockPin,Control,{Address,}[Value{,Value...}]{,Label}

The curly braces around Address means it's optional.

If you don't need to send an address, leave it out.
Then put the HIGHBYTE data inside the square brackets.
<br>

The Altruist
- 22nd March 2010, 04:49
This is a trimmed down version of my code. And frankly, nothing is working. I'm not a hardware guy, so I can't tell if my setup is wired wrong. The guy I work with put it together for me. He's a professional so I'm not going to doubt him. But something, somewhere, isn't working.



;@ __CONFIG _HS_OSC & _WDT_OFF

DEFINE OSC 20
DEFINE ADC_BITS 10 '10-bit ADC
DEFINE I2C_SLOW 1

' Define used register flags
SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag
BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full
R_W VAR SSPSTAT.2 ' SSP (I2C) Read/Write
D_A VAR SSPSTAT.5 ' SSP (I2C) Data/Address
CKP VAR SSPCON.4 ' SSP (I2C) SCK Release Control
SSPEN VAR SSPCON.5 ' SSP (I2C) Enable
SSPOV VAR SSPCON.6 ' SSP (I2C) Receive Overflow Indicator
WCOL VAR SSPCON.7 ' SSP (I2C) Write Collision Detect
ADCGO VAR ADCON0.2 ' ADC GO /DONE bit: High to start. Automatically goes low when finished.


' Define constants
I2Caddress CON $12 * 2 ' Make our address twice the actual address (bit shifted left)
BUFFERSIZE CON $10 ' 16 Word addresses
BUFFERTOP CON BUFFERSIZE - 1 ' Top of Buffer
DATASIZE CON 20


' Allocate RAM
modLevel VAR WORD[BUFFERSIZE]' Modulation Level '32
dataout VAR BYTE[2] ' Data out array '18
result VAR WORD ' ADC result '2
Counter VAR BYTE ' Counter for Arrays '1
Iter VAR BYTE ' Generic Iterator '1
compHi VAR WORD ' Comparison Hi Value '2
compLo VAR WORD ' Comparison Lo Value '2
TempWord VAR WORD ' Swap Variable



' Initialize ports and directions
ADCON0 = $81 ' Clock /32
ADCON1 = $81 ' PORTA.0 analog
' TRISB.1 = 1 ' Pin for SDA
' TRISB.4 = 1 ' Pin for SCL
TRISB.1 = 0 ' Pin for SDA
TRISB.4 = 0 ' Pin for SCL

TRISA.2 = 1 ' Pin RA.2 for AN2
TRISA.3 = 0
TRISA.4 = 0

mainloop: ' Main program loop
'/////////////////////////////////////////////////////////////////////////////
'This is the portion I'm testing out
'\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\
result = 512
result = result << 2
I2CWRITE PORTB.1, PORTB.4, $9C, [result.HIGHBYTE, result.LOWBYTE]



loopforfun:
GOTO loopforfun
'//////////////////////////////////////////////////////////////////////////////

mackrackit
- 22nd March 2010, 04:59
You say nothing is working. Is there a LED on board that can be made to blink to see if the chip is even running?

This line bothers me


;@ __CONFIG _HS_OSC & _WDT_OFF

I take it you are using the default in the inc file?

The Altruist
- 22nd March 2010, 06:25
Actually, that's something I had not considered.
Let me go do some research, and I'll get back with an answer to that.

Byte_Butcher
- 22nd March 2010, 15:13
And frankly, nothing is working. I'm not a hardware guy, so I can't tell if my setup is wired wrong. The guy I work with put it together for me. He's a professional so I'm not going to doubt him. But something, somewhere, isn't working.

Since someone else built the hardware for you, check and make sure that there is a resistor to pull MCLR high.

I just wasted a big chunk of my weekend trying to figure out what configuration fuses and register(s) weren't configured right on a "new to me" chip.
Turned out I forgot to pull MCLR high, so the chip wasn't running at all. :o



steve

Chris Barron
- 22nd March 2010, 15:29
Do you have appropriate pullup resistors on the I2C clock and data lines ?
I have seen values from 1.2k to 10k work to good effect. The lower the value the less susceptible the signals are to noise

The Altruist
- 23rd March 2010, 01:04
Hm.... false alarm. The DAC chip was bad.
We have it (or at least a simple saw tooth wave demo) working now:


;@ __CONFIG _HS_OSC & _WDT_OFF

DEFINE OSC 20
DEFINE I2C_SLOW 1




' Allocate RAM
result VAR WORD ' ADC result '2
Iter VAR BYTE ' Generic Iterator '1


' Initialize ports and directions
TRISB.1 = 0 ' Pin for SDA
TRISB.4 = 0 ' Pin for SCL


mainloop: ' Main program loop
'This should set the DAC to output.
FOR ITER =0 TO 254
result = ITER
result=result<<4
PAUSE 100
I2CWRITE PORTB.1, PORTB.4, $9C, [result.HIGHBYTE, result.LOWBYTE]
NEXT
FOR ITER =255 TO 1 STEP -1
result = ITER
result=result<<4
PAUSE 100
I2CWRITE PORTB.1, PORTB.4, $9C, [result.HIGHBYTE, result.LOWBYTE]
NEXT
goto mainloop

The Altruist
- 23rd March 2010, 01:32
While I have your attention, I'm puzzling over how to efficiently do a 10-bit by 10-bit division (which will yield a value 0<x<1) then multiply it again by 1023 to get a number (0<=x<=1023). I'd prefer not to use LONG values as they eat up precious RAM, but I also want to keep it reasonably quick. I have plenty of words set up, but no LONGs.
Here's the math:
a, b, and x are WORDs
x=1023*(a-b)/(a+b)
Any thoughts?
EDIT: Oh. Ha ha. I don't even have LONGs to work with. Yeah... that makes a difference now, doesn't it?
The only thing I can conceive of is using a two-fold mechanism that combines this:


'Shift RESULT left 10 times
FOR Iter=1 to 10
RESULT=RESULT<<1
NEXT

with this:


'RESULT= B / A
RESULT=0
WHILE B>A
B=B-A
RESULT=RESULT+1
WEND


The trick is to keep the working value inside 16-bits, but inside 10 bits at the very end.

The Altruist
- 23rd March 2010, 23:57
For those of you wondering, this algorithm gives decently accurate 10-bit ratios with a Big O of (n^2). I hope some one finds it useful.
Bear in mind that the Numerator MUST be smaller than the Denominator, and that the denominator bit-shifted left to be bigger than the Power of 2 you're trying to fit it in. Therefore, don't change the 1024 to 16384 and expect it to work (while still using 16-bit WORDs).



TenBitRatio:
Result=0
while Denominator<1024
Numerator=Numerator<<1
Denominator=Denominator<<1
WEND
while Denominator>0
Digit=0
while Numerator>Denominator
Numerator = Numerator - Denominator
Digit=Digit+1
WEND
Denominator = Denominator>>1
Result = Result << 1
Result = Result + Digit
WEND