![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
How to locate a union at a specific location in memory? |
Posted: Mon Mar 21, 2016 5:43 pm |
|
|
I want a method by which I can write an SFR as a single byte, as well as write to its individual fields that may or may not be 1 bit in size. An example is the SSP1CON1 SFR. It has 5 fields. The first is 4 bits and is called SSPM while the rest are 1 bit long.
If the SSPM was not 4 bits long, I would have just used #byte and #bit and not even posted this question.
I think that by creating a union I can write to this SFR as SSP1CON1 = 0x00 and also write to its field SSP1CON1.SSPM = 0 or SSP1CON1.CKP = 1. Please correct me if I am thinking wrong. How do I achieve this in CCS PIC C? |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Mar 21, 2016 6:52 pm |
|
|
This can be done with struct and #byte. Look at this file to see how
it has been done for the CAN bus registers:
Quote: | c:\program files\picc\drivers\can-18f4580.h |
If you have the CCS IDE, you can use it to make a register header file:
http://www.ccsinfo.com/forum/viewtopic.php?t=54022&start=1 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
Posted: Tue Mar 22, 2016 1:53 am |
|
|
As a general slightly further comment, #byte, can locate any variable at a memory location. So just create the union (if you require this rather than a structure), and then use #byte to locate it. So:
Code: |
//Processor setups
typedef struct {
int8 SSPM:4; //four bits for SSPM
int8 CKP:1; //one bit for CKP
int8 SSPEN:1; //SSPEN
int8 SSPOV:1; //SSPOV
int8 WCOL:1; //WCOL
} sspcon_layout;
union {
sspcon_layout smalls; //smalls accesses the bits etc..
int8 whole; //whole accesses the whole register
} SSPCON;
#byte SSPCON = getenv("SFR:SSPCON1")
//This locates this union at the required address
void main()
{
//Now you can write a byte to the SSPCON1 register with
SSPCON.whole = 0x23;
//Or to the parts with
SSPCON.smalls.SSPM=0x3;
SSPCON.smalls.SSPEN=TRUE;
//and similarly read the parts
if (SSPCON.smalls.WCOL)
{
//here the WCOL bit was set
}
while(TRUE)
{
}
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
|
Posted: Tue Mar 22, 2016 2:51 am |
|
|
That is interesting I must say. I do not understand why these identifiers for the SFRs do not already exist in the file generated by CCS for their compiler. When I read PIC C programs they often write directly to SFRs as if they were variables.
Could you just clarify 1 thing. When I learnt C language and read about unions which was far into the book and was treated like an archaic topic, it said that bitfields are not used much now since they are "slow" among a few other reasons that make them of little use today. In embedded systems the situation is different and we need to use them often.
Do you think that using bitfields (through #bit or defining them in union or struct as you have done) is slow or that they generate code that is not fully optimized for what it is intended to achieve? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
Posted: Tue Mar 22, 2016 4:37 am |
|
|
Single bit bitfields are fast. The PIC has single instruction operations to access fixed bits in a variable. Makes these code as single instructions.
Multi bit bitfields can be slow. You have to read the variable, mask the rest of the bits, take the value you want to write, rotate this to the right location, and OR this into place. Can be several instructions.
Generally, in CCS C, there is almost no need to ever access a register directly. This is why they don't as standard include the defines for these. You can write in excess of 99% of code, and never have to do this. This is an area where CCS differs wildly from any other compiler. So one answer to your question, is 'learn to program in CCS'.....
Every operation needed on the SSP, can be done without such access. |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Tue Mar 22, 2016 7:08 am |
|
|
Ttelmah wrote: | Generally, in CCS C, there is almost no need to ever access a register directly. This is why they don't as standard include the defines for these. You can write in excess of 99% of code, and never have to do this. This is an area where CCS differs wildly from any other compiler. So one answer to your question, is 'learn to program in CCS'..... |
Just last week I encountered such a situation.
Created an "AC" cable tester. The tester it replaces simply ensures that there are no DC shorts/opens. Problem is that in practice, a cable that tests okay can fail when placed into a real system, carrying data.
I had to tailor the code to do a "DC" sweep of the cable, and if good, proceed to an "AC" sweep. There are only 2 data lines, so I chose a PIC with 2 UARTS and looped the TX to RX for each UART through one of the data lines being tested. The AC test starts at the maximum possible baud rate, then ratchets down the speed if the data can't be discerned at the receiving end.
Could not employ the standard CCS #use rs232(), which I needed to turn on, do the test, then disable. I had to instead take direct control of the UART registers. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
Posted: Tue Mar 22, 2016 8:36 am |
|
|
Actually the standard CCS function can allow you to turn the UART's on/off. Do the standard #USE RS232 function, but set the baud rate to zero.
Then 'setup_uart(baud,stream)' with a baud rate, will enable the UART. setup_uart(FALSE,stream), will disable the UART/stream. |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Tue Mar 22, 2016 8:49 am |
|
|
Didn't know about the 0 baud trick to disable. Tried just setting the relevant enable bits off.
Main issue was the #use rs232() would set up the serial ports before I wanted them turned on, which prevented accessing those bits individually for the DC test. This was a problem even if the function where the #use rs232() was placed wasn't actually called, only defined. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
Posted: Tue Mar 22, 2016 9:36 am |
|
|
This is where setting it up with baud=0 in the #USE comes in. This doesn't enable the port at the setup time. Only when you then call the uart_setup.
You can also use the option 'NOINIT', and then the baud rate will be setup, but the UART will still not be enabled.
You can then just use setup_uart(TRUE,STREAM); to start it. |
|
![](templates/subSilver/images/spacer.gif) |
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
|
Posted: Sun Apr 03, 2016 2:41 pm |
|
|
how does one do the following:
(1) How do I create a constant value of arbitrary bit length in this struct e.g how to have two permanent high bits between CKP and SSPEN?
(2) If the struct is not aligned to byte boundary, how do I find out how the final struct shall be like? e.g if I have a 9 bit long struct with the last field being 1 bit long, will it go into the MSB of the second byte or LSB?
(3) Also, what if the last field is 4 bits long and split between the first and second bytes? Will the 2 MSB of this 4 bit field be contiguous with the first 2 bits under all compilers or will they be split apart?
Everyone tells me that the answer to these questions is dependant on the target hardware i.e PIC18 in this case and the compiler. Thus, I am forced to ask this here. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Sun Apr 03, 2016 5:21 pm |
|
|
The easy answer, one that gains you the most knowledge that you'll remember, is to cut minimal code, compile and look at the listing.
Really, maybe 20 lines fo code and you'll see what is happening.
Not trying to be a smart alec but as you've found out what works for one series of PICs doesn't necessrily hold for another. The listing WILL show you.
Within an hour, after 2 or 3 programs, you'll see your answer AND understand it.
Jay |
|
![](templates/subSilver/images/spacer.gif) |
matrixofdynamism
Joined: 06 Dec 2010 Posts: 25
|
OK I will write test programs |
Posted: Sun Apr 03, 2016 5:29 pm |
|
|
I will write test programs and get to the bottom of this. When you say that what holds for one PIC may not hold for another, does that refer to PIC families like PIC10, PIC16, PIC18, PIC24, dsPIC e.t.c?
Don't they all have the same "architecture" so in these specific things they must behave identically? |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Sun Apr 03, 2016 7:07 pm |
|
|
re:
Don't they all have the same "architecture" so in these specific things they must behave identically?
Nope. 16 bit PICs are different than 8 bits and dsPICs, well they are 'fun'. I don't have enough days left to figure out the 'details' of the families, that's why I settled on one 16F and one 18F PIC. Haven't found a product I can't make with them, saves on endless hours of head scratching.
Jay |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
Posted: Mon Apr 04, 2016 12:08 am |
|
|
Bitfields fill from the bottom up.
LSb -> MSb
LSB -> MSB
You can't declare bits as 'permanently high'. You just have to declare dummy bits, and _initialise_ these to the value you want. |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Apr 04, 2016 2:06 am |
|
|
matrixofdynamism wrote: | When I learnt C language and read about unions which was far into the book and was treated like an archaic topic, it said that bitfields are not used much now since they are "slow" among a few other reasons that make them of little use today. |
and
Quote: | Do you think that using bitfields (through #bit or defining them in union or struct as you have done) is slow |
With modern hardware whether they are "slow" or is far less relevant today than it was historically, when processor speeds were far slower an memory far more limited than today.
The speed of implemenation of bitfields, and other stuff, is hgihly dependant on the hardware of the target processor. Processors that provide hardware or microcoded support for single bits, which is reasonably common and very common/standard on processors intended for embedded use, will support some faster bit fields, and probably some slower. I don't know of any processor that ever provided hardware support for arbitrary length bit fields. So, probably, dealing with a seven bit field spread part in one byte and part in another is never going to be "fast", no matter what processor you target. Modern general purpose processors have far less need to process small numbers of bits, so they often don't support it in hardare. Instead they are based around much longer bit data. In most PC processors, dealing with bytes is considerably slower than dealing with 32 or even 64 bit words: for overall portability it's best to use int for loop counters even for counts of tess than ten as the int, regardless of what the actual length, will generally be the "native" and most efficient of all the data types.
But, I repeat, speed is - generally - not all that important. A lot of beginning embedded coders seem to be obsessed with speed, and treat it as the only thing that matters. They use "fast_io", generally without understanding what it does and what is required for it's use, because, presumably, it is "fast". Whereas experienced CCS programmers almost never use it, and will only use it if its absolutely necessary.
Quote: | In embedded systems the situation is different and we need to use them often. |
I'm not so sure that's really the case. Yes, they can be useful, but they can also be confusing, suffer from alignment issues and limitations, and are often not portable without modification from one architecture to another. Multiple bit fields (fields of more than one bit) suffer from implementation peculiarities, such as requiring hidden behind the scenes read-modify-writes which can mess up their use, especially with SFRs.
I rarely use bitfields. When I do, I tend to soon change to another method of implementation for one reason or another.
Quote: | they generate code that is not fully optimized for what it is intended to achieve? |
No matter what you do, using any high level language will produce code that is not "fully optimised". There are also optimisation tradeoffs, generally memory for speed. As I said above, raw speed is generally not worth chasing. Optimisation is not the be all and end all of coding. The best "optimisation" gains are most often acheived not by worrying about the detail, but by developing efficient algorithms and avoiding unnecessary work. Essentially, what I am saying is that its best to learn how to program efficiently, and only then is it worth worrying about fine tweaking code for optimal performance.
So, why do you need "optimal" handling of bitfields? Note I write "need", not "want". |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|