View previous topic :: View next topic |
Author |
Message |
Steve Byrne Guest
|
Shifting data out of a pin to load a pll register correctly |
Posted: Fri Jul 07, 2006 7:27 pm |
|
|
Hi all, I am having a difficult time trying to get my head around the
best method of shifting data out of a pin so as to load the registers
correctly in a pll, so perhaps some of you can help me out.
The device i am using is a ADF4110 by analog devices the register bit width that I am trying to load has a total of 24 bits. But that register is made up like so.
[ >>>>>>>>>>>>>>>> N Register <<<<<<<<<<<<<<<<<<<<<<]
CP [ 13 BIT B COUNTER ] 6 BIT A COUNTER Control bits
[] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] []
I have 4 variables each 8 bits long. The width of each of the variables
does not exceed the bit width of each counter.
CP, BCOUNT, ACOUNT, CB
So in-order to load the register correctly I need to shift out the msb of
each variable into their respective counters in the correct order. What would be a good method to do this. ? I was thinking of breaking each
part down into individual for loops, load 3bits, 13bits etc but was not sure.
I am using pins RC3 for clock and RC4 For the data out pin.
A small example would be very helpful to get me going in the right direction.
Thanks for your help Steve. |
|
|
epideath
Joined: 07 Jun 2006 Posts: 47
|
|
Posted: Fri Jul 07, 2006 9:35 pm |
|
|
I would probably do something like this:
Code: |
int8 i;
int32 command = 0;
int8 CP = 1;
int16 BCOUNT=0x1234;
int8 ACOUNT= 0x12;
int8 CB=0x07;
command = (CP<<23);
command |= (((int32)BCOUNT & 0x1FFF)<<10);
command |= (((int16)ACOUNT & 0x3F)<<4);
command |= (CB & 0x0F);
for(i=0; i<24; i++) {
output_bit(PIN_B4, command & 1);
command >>=1;
output_low(PIN_B3);
output_high(PIN_B3);
}
//if you need to go MSB first then just reverse it.
//for(i=0;i<24;i++) {
// output_bit(PIN_B4, bit_test(command, 23)); //bit 23
// command <<= 1;
// clock it out.
//}
|
Hope this helps. |
|
|
Guest
|
|
Posted: Sat Jul 08, 2006 1:56 pm |
|
|
Hi epideath.
Thanks for taking the time to write back.
From the code It looks like you mask each value of the variable
with the actual bit width of each variable first.
like the bcount is only 12 bits wide, so that gets anded with FFF and
then you shift those 12 bits left until the MSB of bcount is at bit position
21 of the 32bit int command. This looks ok.
in the code you have
command |= (((int32)BCOUNT & 0x1FFF)<<10);
What does the | do in the code line above.
and in the for loop
output_bit(PIN_B4, command & 1);
what does the command & 1 do
Thanks again Steve. |
|
|
epideath
Joined: 07 Jun 2006 Posts: 47
|
|
Posted: Sat Jul 08, 2006 3:41 pm |
|
|
The |= will OR the bits with the bits already set in command.
The & is AND so in this case we are masking all bits except the first. (command AND 0x01) It will be either a 0 or 1.
Hope this helps. |
|
|
Guest
|
|
Posted: Sun Jul 09, 2006 12:15 am |
|
|
Well getting closer,
I am curious as to why the values need to be ored and anded.
is there a particular reason why ?, I cant seem to see it.
command = (CP<<23);
command |= (((int32)BCOUNT & 0x1FFF)<<10);
command |= (((int16)ACOUNT & 0x3F)<<4);
command |= (CB & 0x0F);
Can I not just shift the values in the bcount,acount into the correct
LSB bit position of "command" like so and then output the command
variable.
command = (CP<<23);
command = (BCOUNT<<10);
command = (ACOUNT<<4);
command = (CB & 0x0F);
My thinking was that as long as the value of bcount,acount did not
exceed the bit width of the actual register I would be ok. Am I way off
base, what you think.
Thanks again Steve |
|
|
epideath
Joined: 07 Jun 2006 Posts: 47
|
|
Posted: Sun Jul 09, 2006 10:26 am |
|
|
If you don't OR the bits as you suggested then the value of command will be replaced each time with the new shifted value. So in your example the value of command would equal the shifted value of CB the last statement.
To do what you need to do can probably be done in several ways. I jsut gave you one idea. Basically what you are trying to do is this:
Say
CP = 1; 0b00000001
BCOUNT = 0b0001111111111111
ACOUNT = 0b00111111
CB = 0b00001111
The reason for the AND is to mask off any extra bits. This can probably be removed. As long as you know the values of these will never exceed the bit field widths you stated earlier.
what we are attempting to do is this. we start with a 32 bit value, we only need 24 bits total though
Code: |
int32 command = 0b00000000 00000000 00000000 00000000
so after we shift CP 23 bits we will have the following
command = 0b00000000 10000000 00000000 000000000
Then we shift the BCOUNT value and OR it with what was in CP already
command = 0b00000000 10000000 00000000 00000000
|= 0b00000000 01111111 11111100 00000000
command = 0b00000000 11111111 11111100 00000000
Then we OR the ACOUNT value with command as follows:
command = 0b00000000 11111111 11111100 00000000
|= 0b00000011 11110000
command = 0b00000000 11111111 11111111 11110000
Then finally we OR the last value CP
command = 0b00000000 11111111 11111111 11110000
|= 0b00001111
command = 0b00000000 11111111 11111111 11111111
|
So you can see that if we don't mask off the extra bits and they happen to be on when we OR the values they could over write bits already set. If they are forced to zero then they will never over write bits previously set.
There are other ways of doing what you need. Another way that this can be done is to send the data out each time you test a new bit. I personally don't think this is as efficient or easier to understand. But it could go something like below.
Code: |
output_bit(PIN_B4, bit_test(CP,0)); //set output to 0 or 1 based on bit test
output_low(PIN_B3);
output_high(PIN_B3);
for(i=0; i<14;i++) {
output_bit(PIN_B4, bit_test(BCOUNT,i)); send each bit out
output_low(PIN_B3);
output_high(PIN_B3);
}
for(i=0; i<6;i++) {
output_bit(PIN_B4, bit_test(ACOUNT,i)); send each bit out
output_low(PIN_B3);
output_high(PIN_B3);
}
for(i=0; i<4;i++) {
output_bit(PIN_B4, bit_test(CP,i)); send each bit out
output_low(PIN_B3);
output_high(PIN_B3);
}
|
Well as you can see this will require a bit more time to execute and it will most likely take up more memory.
There are other ways to do what you want, there may even be a better way to do than what I originally posted. If there is then maybe someone else can post it. The way that I typically do this sort of thing is as I originally posted.
Regards |
|
|
Guest
|
|
Posted: Sun Jul 09, 2006 11:10 am |
|
|
Ah I see !
The last method is more readable, but thats just because I am not used
to the original method with the extra bit shifting etc. I will try both
methods and see if there is much of a difference in the size of the code.
Thanks very much for your help. Its difficult to find resources on how
to do this type of coding. I appreciate the time you took to explain
it.
Best regards Steve. |
|
|
|