I2C communication with SAA1057

For Flowcode users to discuss projects, flowcharts, and any other issues related to Flowcode 6.

Moderator: Benj

Post Reply
headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

I2C communication with SAA1057

Post by headhuntergr »

Hello!
I am using a very old part which is SAA1057. It uses i2c (probably) communication.
http://www.pira.cz/pdf/SAA1057.pdf here is the datasheet.


Speed must be equal or less than 100KHz

To initialize the chip you have to send either:
1) 16 clocks and then word B followed by word A or
2) Send word B twice and then send word A

I have attached my program and i wanted to ask if this is the correct way to do it.

Thank you :)
Attachments
AMPll.fcfx
(9.78 KiB) Downloaded 415 times

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

Update:

Doesn't seem to want to communicate for some reason. Tried everything.

Brendan
Posts: 243
Joined: Tue Nov 27, 2012 12:53 pm
Location: Cambridge, UK
Has thanked: 140 times
Been thanked: 118 times
Contact:

Re: I2C communication with SAA1057

Post by Brendan »

Hi there.

I'm sorry I've no time currently to help in any detail, but a quick glance at the datasheet confirms this chip doesn't actually employ I2C at-all.

All you're doing is clocking single bits into a 16-bit wide shift register (repeated to successively program Latch-A and Latch-B), so you should simply bit-bang the latch-enable, clock and data bits in serial fashion, specific to the device as described. I would start off clocking data at a much slower rate than maximum to ensure that data always has the correct logical level before clocking each bit.

I2C is only mentioned as the chip allows the data pins to be common to I2C devices on the same data bus, without interference to the chip.

Hope this helps.


All the best,

Brendan

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

Thank you for your reply Brendan.


Here is a pic of the init sequence i was sending.
Image

And WordB up close
Image


And WordA
Image

I'm sending a Uint on it as WordA (512 up to 1800).

Many projects i saw usually implement i2c routines to work with it. Have no idea (noob alert) how to do this in FL6 without i2c.

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

Hmmm
Can anyone help me to create a macro so i can bit bang my 15bit config words?

regards

Brendan
Posts: 243
Joined: Tue Nov 27, 2012 12:53 pm
Location: Cambridge, UK
Has thanked: 140 times
Been thanked: 118 times
Contact:

Re: I2C communication with SAA1057

Post by Brendan »

Hello again.

Once you've established your register values then you need to extract the individual bits and send them serially.

For example, if I had a value in 'SendByte' that I wanted to send in this fashion (MS bit first), this is one of a number of ways you could do it...

1. Create a loop that counts eight times (for a Byte value of-course)
2. Declare LoopCount variable starting value of '8' before the loop starts
3. On each pass of the loop, use bit-shift-compare and send each bit in the following manner...
4. LoopCount = LoopCount - 1
5. BitToSend = (SendByte >> LoopCount) AND 1
6. Send the bit in BitToSend
7. If LoopCount < 1 then exit loop

Basically, step 4 shifts the Byte to the right by the value of LoopCount, so by AND'ing with the value of '1' gives you the value of the next bit.

Another example would be to make a larger variable for processing larger bit-strings (particularly on an 8-bit PIC), progressively decrementing the high bit of the compare variable in each loop pass, and then AND'ing the two variables to extract the bit of concern (e.g. IF result > 0 as the bit would still represent its true value). This therefore reserves RAM for the variables and avoids possible (reported) issues by bit-shifting values much larger than the bus width of the PIC you're using.

Yet another example, if you're not worried about preserving the original data string or are passing data to another variable for processing, would simply be to divide the data string by two on each pass (e.g. BitString = BitString >> 1) and 'AND' with 1 on each pass for the current bit value to send. However, you'll have noticed that this example sends the LS bits first.

Many such ways to skin a cat, each with its own merits, and I'm sure others could suggest more succinct alternatives than mine. Just giving you a flavour of bit-wise serial processing though :)

All the best,

Brendan

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

Thank you for your reply.

I got a bit confused but i will look into it probably in the morning because i was fiddling with this all day and i'm wasted.

Will try to find examples if possible maybe they will help too.

Brendan
Posts: 243
Joined: Tue Nov 27, 2012 12:53 pm
Location: Cambridge, UK
Has thanked: 140 times
Been thanked: 118 times
Contact:

Re: I2C communication with SAA1057

Post by Brendan »

I understand and empathise...

If you can follow my first example, I'm sure things will quickly click into place :)

Think of a string of 1's and 0's just typed on an old-style typewriter, where the amount you temporarily move the carriage to the right is decided by the value in LoopCount, and the bit under the head is the bit to send.


All the best,

Brendan

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

So in total i have to send 2 bytes for the first wordb, 2 more bytes for the worb again and then 2 more bytes for wordA, this should initialize the chip.

Then everytime i need to change the frequency value i will only need to send wordA.

Do i have to reset the loopcount to 8 everytime i exit the loop right?

The BitToSend variable has to be a boolean?

To send the bit it has to be sent out followed immediately by the clock pin and then back to 0 followed by a delay and then to the next bit correct?

Thank's

Brendan
Posts: 243
Joined: Tue Nov 27, 2012 12:53 pm
Location: Cambridge, UK
Has thanked: 140 times
Been thanked: 118 times
Contact:

Re: I2C communication with SAA1057

Post by Brendan »

So in total i have to send 2 bytes for the first wordb, 2 more bytes for the worb again and then 2 more bytes for wordA, this should initialize the chip.
Yes, I believe that should do it, though haven't studied the datasheet in any depth as I'm presently working on an urgent consumer project.
Then everytime i need to change the frequency value i will only need to send wordA.
It outwardly looks that way, though if you split the processing of WordA and WordB to separate macros, this would enable you to separately focus on each to ensure your data's correct, then simply call one or both as occasion demands. I would personally have a single macro updating/reaffirming both registers on each occasion, as this will simplify your code and avoid having to worry about whether the shift-register was in sync or needed a reset during normal operation.
Do i have to reset the loopcount to 8 everytime i exit the loop right?
I would highly advise resetting LoopCount immediately before you started the loop. This would avoid the potential for LoopCount being altered in any way elsewhere in your program, though normally because LoopCount is (or could be) shared with different program loops so would (should) usually be set immediately before each loop anyway. In your case though, I would create a loop to process an entire 16-bit word. Datasheet Fig.2 suggests least-significant bit first, so simply...

LoopCount = 0 (loop starting value)
Data_Word = the 16 data bits to send
Compare_Word (a 16-bit variable used for loop word compare, where only a single bit in Compare_Word is set high in each case)
SendBit (Boolean)

The loop...

Compare_Word = 1 << LoopCount ...makes Compare_Word a solitary bit value that represents the data bit 'value' that you're presently interested in.

SendBit = (Data_Word AND Compare_Word) >> LoopCount ...Compares the two bit values and shifts (divides) the representative bit value back down so that it cannot be greater than a boolean. For example, if you were comparing a bit value of (say) '32', you must first divide 32 by 32 (e.g. >> 5) to get a maximum value of 1 before assigning to the boolean SendBit. Incidentally, using bit-shift to divide in this way is preferable to using a mathematical divide function, such as when X >> 0 = X, whereas X / 0 would cause a 'divide by zero' error.

Send the bit ...I would suggest creating a macro that specifically handles data and clock timings.

LoopCount = LoopCount + 1 ...This will represent the next bit value to be set to Compare_Word for AND'ing with the Data_Word (only the single bit set high in Compare_Word, will be taken into account).

If LoopCount > 15 then exit loop

The BitToSend variable has to be a boolean?
In practice it doesn't have to be, though a Boolean is easier to deal with and better for debug as it relates to just the bit being sent and can never be anything more.
To send the bit it has to be sent out followed immediately by the clock pin and then back to 0 followed by a delay and then to the next bit correct?
Yes, though you must first set the data, allow a small propagation delay, then shift the clock pin high then delay then low, then a further propagation delay before changing the data pin, and so on. Advisedly, a minimum delay between any change on any line. As communication speed is not of the essence for scoping and test and debug, I would start off with a slow data rate of 10kHz for bags of margin initially, with timings between edges as follows:

Set DLEN + 300us

then

Set Data + Wait 300us + Clock High + Wait 300us + Clock Low + 300us ...and repeat for each bit sent.

Set the delay in us to a variable, then you can simply increase the speed later if desired, once you've established that the data is correct and valid.


All the best,

Brendan

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

Thank's Brendan you made it quite clear.
I'll try it out and let you know :)

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

I made a quick & dirty program, doesn't work for now but i'm looking into it.
Should i make the loopcount at 14?
Attachments
AMPll.fcfx
(29.73 KiB) Downloaded 265 times

headhuntergr
Posts: 50
Joined: Fri Feb 28, 2014 7:25 am
Has thanked: 34 times
Been thanked: 5 times
Contact:

Re: I2C communication with SAA1057

Post by headhuntergr »

Image

This is what i get on the output, i might have to place a delay between the init steps to help the DLEN stay down for some time.
What mothers be it that i have an extra 1 on wordA which should be a zero. The first bit if it's 1 then it has to be a wordB and if it's 0 it is a WordA.


When i send just the wordA it simply sends one bit and that's it..

Brendan
Posts: 243
Joined: Tue Nov 27, 2012 12:53 pm
Location: Cambridge, UK
Has thanked: 140 times
Been thanked: 118 times
Contact:

Re: I2C communication with SAA1057

Post by Brendan »

Hello Again.

First, your data is looking considerably better now that you've slowed things down :)

I've taken a quick look at your code and my first advice is to get rid of the decision operator and connection points in order to exit your loops.
Connection points , while 'OK' in many instances, are generally used as a last resort, though shouldn't be used in this way.

Edit the Loop component and set the parameters to...

Loop Until
LoopCount > 15
Test at the end

The loop will then exit at the appropriate value of LoopCount.

Regarding code flow, make things easier on yourself with macro's that build WordA and WordB from global variables that represent the various register sections, and (I would suggest) name the variables as per the datasheet identifiers to keep things intuitive. It is then a simple matter to change whatever settings you wish and then simply call the macro to send the word.

For example, if (say) the first four least-significant bits of a control word represented a function called 'AAA', the next six bits represented another function called 'JJJ', the next two bits represented a function called 'PPP', and the last four bits represented 'ZZZ', then...

1. Change any of the control values in your program flow.
2. Call the macro to resend all the values.

In the above example, the sending macro when called would first build the data string from the individual control variables as follows...
SentWord = (AAA and 15) + ((JJJ and 63) << 4) + ((PPP and 3) << 10) + ((ZZZ and 15) << 12)

AND'ing here isn't strictly necessary, though simply ensures that anything else that could possibly be contained in the bytes is excluded for more robust code.

The word is then sent to the PLL chip and all registers are then updated accordingly.

I would first focus on creating and naming the control variables as defined in the datasheet, then first try some arbitrary values to check that you're sending the words you expect.
.. but do get rid of those nasty loop exit connection points first :wink:

EDIT: Incidentally, as BitToSend is a Boolean, when sending to port B5 you should left-shift the bit to match the value of the port binary bit value. B5 = BitToSend on a masked output won't work as BitToSend is never greater than '1', but B5 = BitToSend << 5 should. Although uninitialised, I'd also 'disconnect' or remove the I2C component as it's not being used.

All the best,
Brendan

Post Reply