CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

losing my mind? or can I not figure out a simple for() loop?
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
thefloyd



Joined: 02 Sep 2009
Posts: 46

View user's profile Send private message

PostPosted: Sun Sep 30, 2012 4:28 pm     Reply with quote

It's not necessarily how fast I can clock the bits out (though that does come into play), but a 50us low is considered a latch.

Basically I'm working with a string of LEDs driven by WS2811 ICs. these basically take 24 bits of data (8 bit red, green, blue), shift it in, and cascade the next 24 bits over to the next chip (and so on and so on down the line). Once you hold the data line low for 50+us, the ICs along the string all latch the data and display the incoming data.

What I'm seeing in my for() loop SEEMS to be 50us+ long low periods, causing the first LED to latch and the rest of the data never making it down the string (currently 100 LEDs long). When I do the bit tests individually all typed out, the data makes it all the way down the string and the expected result (LEDs do what I'm asking them to) happens.
Ttelmah



Joined: 11 Mar 2010
Posts: 19514

View user's profile Send private message

PostPosted: Mon Oct 01, 2012 3:00 am     Reply with quote

Try with the faster code.

Are you _sure_ your chip really is clocking at 64MHz?.

Historically, on some compiler versions, the settings as you have them, don't correctly enable the PLL. You have to have the setup_oscillator command to make it work.

I'd guess you are actually running at 16MHz, then the long time needed for the bit_test using a variable, _would_ take about 50+uSec, and 'voila' you have your problem.

Much faster though to do the single rotation as shown.

It takes about 750uSec to send the 24bits at 16Mhz using the existing code.
Average of 32uSec, but the earliest bits are the slowest, taking 52.5uSec for the first bit, 51.25 for the second, etc..

Using my version (two typing errors, but they are obvious), it takes just 4.5uSec/bit at the same clock rate, and the time between bits is constant.

Best Wishes
thefloyd



Joined: 02 Sep 2009
Posts: 46

View user's profile Send private message

PostPosted: Mon Oct 01, 2012 4:23 pm     Reply with quote

Ttelmah wrote:
Try with the faster code.

Are you _sure_ your chip really is clocking at 64MHz?.

Historically, on some compiler versions, the settings as you have them, don't correctly enable the PLL. You have to have the setup_oscillator command to make it work.

I'd guess you are actually running at 16MHz, then the long time needed for the bit_test using a variable, _would_ take about 50+uSec, and 'voila' you have your problem.

Much faster though to do the single rotation as shown.

It takes about 750uSec to send the 24bits at 16Mhz using the existing code.
Average of 32uSec, but the earliest bits are the slowest, taking 52.5uSec for the first bit, 51.25 for the second, etc..

Using my version (two typing errors, but they are obvious), it takes just 4.5uSec/bit at the same clock rate, and the time between bits is constant.

Best Wishes


I'm pretty sure about 64mhz. I DID have issues using the internal osc and asking it to run at 64Mhz. While it happily acted like it was running at 64mhz when I tried using RS232 all I got was garbage. When I changed the clock down to 16mhz in that setup RS232 was fine. My current setup is using an external 16mhz crystal and PLL enabled. I've also used RS232 to debug in this setup and things are working as expected - so I don't yet have a reason to believe I'm _not_ at 64mhz this time.

I will try with your faster code tonight. Appreciate the insight, hopefully it'll get me to where I need to be. As a casual hobbyist bit operations have always been my weak point (and'ing/or'ing/shifting/etc are hard to grasp, dunno why).
thefloyd



Joined: 02 Sep 2009
Posts: 46

View user's profile Send private message

PostPosted: Mon Oct 01, 2012 8:47 pm     Reply with quote

Ttelmah wrote:
Try with the faster code.

Are you _sure_ your chip really is clocking at 64MHz?.

Historically, on some compiler versions, the settings as you have them, don't correctly enable the PLL. You have to have the setup_oscillator command to make it work.

I'd guess you are actually running at 16MHz, then the long time needed for the bit_test using a variable, _would_ take about 50+uSec, and 'voila' you have your problem.

Much faster though to do the single rotation as shown.

It takes about 750uSec to send the 24bits at 16Mhz using the existing code.
Average of 32uSec, but the earliest bits are the slowest, taking 52.5uSec for the first bit, 51.25 for the second, etc..

Using my version (two typing errors, but they are obvious), it takes just 4.5uSec/bit at the same clock rate, and the time between bits is constant.

Best Wishes


Amazing. Your code works _beautifully_. I get the basics behind what it's doing.. but I don't 'get it'. Time to start reading more..
Ttelmah



Joined: 11 Mar 2010
Posts: 19514

View user's profile Send private message

PostPosted: Tue Oct 02, 2012 12:48 am     Reply with quote

The key is understanding how bit_test works.

If used with a constant value, it works out in advance what byte is involved, and used the processor bit test instruction. Singe machine cycle.

With a variable though there is a problem. What it does is starts with a 'temporary' variable matching the size of the object you want to test. So in your case an int32. It then loads this with '1', and rotates this the number of times needed to get to the bit needed. So effectively in your case, it codes as:
Code:

int1 test_bit(int32 val, int8 num){
   int32 mask=1;
   int8 ctr;
   for (ctr=0;ctr<num;ctr++) {
       mask*=2;
   }
   return ((val & mask)!=0);
}

So in your first case, with '23' as the bit number, it has to loop 23 times rotating the four byte variable. In all, it performs 23,22,21,.....2,1,0 rotations. A total of 276 4byte rotations, and 24 4byte AND operations!.....

Now my alternative hits it from the other end. You have your 24bit number stored in a variable, whose contents can be destroyed by the output. The first time round you want to send bit 23, the next time bit 22 etc...
So I code the first output, as a constant bit test (testing bit 23). Fast, gets rid of the need to perform the 4byte 'AND'.
Then I just rotate the variable _once_. What was bit 22, is now in bit 23, so the same constant test works. Each time round the loop, I just rotate once, and test. The counter becomes a simple 24* counter (no need for it to match the bit number involved), and each loop then has a single 4byte rotation, a bit test, and the increment/test of the counter. A total of just 23*4 rotations. Also, because there is no counting to the bit number, the operation takes constant time. About 5* faster on average, and nearly ten time faster on the 'worst case' bits.

Perhaps the big lesson is to 'beware' of bit test using a variable, especially with a large number like this. It can take a lot of processor work.....

However I still have to suggest you go back and triple check the processor is getting the 64MHz, since at this speed, the bit_test version should not cause the timing you are describing - I have stop-watched it, and at 64MHz, the longest bit time should still be only about 13uSec. It only gets to the timing you are reporting, and would give a problem, if your clock is not 64MHz....

Best Wishes
thefloyd



Joined: 02 Sep 2009
Posts: 46

View user's profile Send private message

PostPosted: Tue Oct 02, 2012 8:04 am     Reply with quote

Thanks for taking the time out to explain this to me in a little more detail, it certainly clarifies things. I know my strong and weak points and code optimization isn't one of my stronger points (though I'm learning :D).. I figured I'd just throw more power at the problem as that wasn't an issue in this particular case.. funny how that doesn't always seem to solve the problem Smile

I will double check tonight to see if I can be certain the PIC is operating at 64mhz. Quick thought - you say the timings I'd be seeing are in line with a device operating at 16mhz - isn't the internal PIC clock OSC/4? So even if I was at 64mhz my PIC would be executing instructions at 16mhz.. is that the missing link here?

Also, if you don't mind schooling me a bit more (or pointing me in the direction of a good read) .. how does this_led*=2 end up rotating the bits such that I'm shifting my next lower bit into the 23rd spot repeatedly? (And I'm assuming I'm getting zeros in their empty spaces as they shift? Not that it matters.. just curious).

If my data were 8 bit and I was testing the 8th bit, would it look like this?

10111011 <- starting data
01110110 <- first iteration
11101100 <- second iteration
11011000 ..
10110000 ..
01100000 ..

.. etc as I worked my way through the loop?

Or does the arithmetic "wrap around" such that the 8th bit would now be the 1st bit?

thanks again for your help.
Ttelmah



Joined: 11 Mar 2010
Posts: 19514

View user's profile Send private message

PostPosted: Tue Oct 02, 2012 8:17 am     Reply with quote

No, I am allowing for that. 64MHz = 16MIPS.
I stop watched the function in MPLAB, to get the actual times involved.

Yes, you can use <<=1 to move the bits round or *=2. Both basically do the same. The compiler is smart enough to realise it can multiply by two, by simply shifting the number. Bits at the bottom, are filled with zeros as you shift, so are as you show.

You could also use the CCS 'rotate_left' instruction, which then _does_ wrap the bit round, but with your real value, you'd have to rotate another 8 times to get back to the starting number, which would take longer than just reloading it.

Best Wishes
thefloyd



Joined: 02 Sep 2009
Posts: 46

View user's profile Send private message

PostPosted: Tue Oct 02, 2012 8:50 am     Reply with quote

Ttelmah wrote:
No, I am allowing for that. 64MHz = 16MIPS.
I stop watched the function in MPLAB, to get the actual times involved.

Yes, you can use <<=1 to move the bits round or *=2. Both basically do the same. The compiler is smart enough to realise it can multiply by two, by simply shifting the number. Bits at the bottom, are filled with zeros as you shift, so are as you show.

You could also use the CCS 'rotate_left' instruction, which then _does_ wrap the bit round, but with your real value, you'd have to rotate another 8 times to get back to the starting number, which would take longer than just reloading it.

Best Wishes


Thanks. I just had an 'A ha!' moment.

While the compiler might have been smart enough to realize it can multiply by two by simply shifting the bits, *I* wasn't. Though it makes perfect sense, I never thought of it that way.

I have a lot to learn.. Smile

When I get home tonight I'll see what I can figure out with regards to the OSC. As I said earlier, I did have a problem trying to get the internal osc going at 64mhz (and it was obvious, despite the proper #use delay, RS232 was garbage until I changed the delay to 16000000) I quit trying to debug that because it was just easier to sub in a 16mhz resonator I had at my desk - and with a #use delay of 64000000 RS232 is working properly. I'll try and time an LED blink but I'd be surprised if I wasn't running at the 64mhz this time. My current oscillator fuses are:

#FUSES HSH
#FUSES PLLEN

#use delay(clock=64000000)

With a 16mhz ceramic resonator hooked up to the OSC pins.
thefloyd



Joined: 02 Sep 2009
Posts: 46

View user's profile Send private message

PostPosted: Sun Oct 07, 2012 8:44 am     Reply with quote

I can definitely say with reasonable certainty that this setup is running at 64mhz:
- RS232 works as expected
- Blinking an LED shows the proper amount of delay given the #use delay setting.

So.. I'm still perplexed. Glad your code got me past my problem, but still a bit unsettled since I don't exactly know what the problem is (since by all indications my code should have worked at 64mhz even with its inefficiencies..)
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group