Difference between revisions of "Embedded Programming Tips for CCS C"

From Mech
Jump to navigationJump to search
 
Line 5: Line 5:
As an example, the CCS library doesn't have a function that will write to PR5 (Timer5 period match register) for devices (such as the PIC18F4431) that have them. However, we can look in the datasheet in the "Special Function Registers" section to find memory address of the SFR we want.
As an example, the CCS library doesn't have a function that will write to PR5 (Timer5 period match register) for devices (such as the PIC18F4431) that have them. However, we can look in the datasheet in the "Special Function Registers" section to find memory address of the SFR we want.


''Note:'' When writing to 16-bit SFRs which may be changing (such as a timer register), it is important to write to the high byte first and write to the low byte second.
''Note:'' When writing to 16-bit SFRs with a high and low byte which may be changing (such as a timer register), it is important to write to the high byte first and write to the low byte second. When reading from the 16-bit register, read the low byte first and the high byte second. The high byte is actually a buffer; writing to the low byte will automatically load the high byte into the register, and reading from the low byte will automatically copy the current value into the high byte register, in a single operation. This prevents the data from changing or rolling over in the time between reading or writing the first and second registers.
For the CCS compiler, you can use the <tt>#byte</tt> preprocessor directive to tell it to place a variable at a specific memory address. Look up the correct memory address in the datasheet (the 0x denotes hexadecimal notation):
<pre>
//put variables at memory location
//put variables at memory location
#byte PR5L=0xF90 //PR5 low byte
#byte PR5L=0xF90 //PR5 low byte
#byte PR5H=0xF91 //PR6 high byte
#byte PR5H=0xF91 //PR6 high byte
</pre>
...
Later in the code, when we want to set the values, we can set it like any other variable:
PR5H = 10000/256;
<pre>
PR5L = 10000%256;
PR5H = 10000/256; //take only high bits
PR5L = 10000%256; //take only low bits
</pre>


Can also use pointers:
Alternatively, we can also use pointers:
<pre>
int8* PR5H;
int8* PR5H;
int8* PRHL;
int8* PRHL;
Line 21: Line 27:
*PR5H = 10000/256;
*PR5H = 10000/256;
*PR5L = 10000%256;
*PR5L = 10000%256;
</pre>

Revision as of 00:26, 9 December 2008

Writing Directly to a Memory Address

When configuring the peripherals of the PIC, one usually checks the PIC's datasheet and manually writes the bits corresponding to the desired settings to the special function registers (SFRs). The CCS library attempts to make things easier by wrapping up the SFRs into function calls such as setup_adc, etc. However, some functionality may be "lost in translation," or the documentation may be so vague that it's easier just to the write the correct bits directly to the SFRs. Unfortunately, the SFR names used in the datasheet are not defined in CCS's device .h files, so we'll have to define them ourselves.

As an example, the CCS library doesn't have a function that will write to PR5 (Timer5 period match register) for devices (such as the PIC18F4431) that have them. However, we can look in the datasheet in the "Special Function Registers" section to find memory address of the SFR we want.

Note: When writing to 16-bit SFRs with a high and low byte which may be changing (such as a timer register), it is important to write to the high byte first and write to the low byte second. When reading from the 16-bit register, read the low byte first and the high byte second. The high byte is actually a buffer; writing to the low byte will automatically load the high byte into the register, and reading from the low byte will automatically copy the current value into the high byte register, in a single operation. This prevents the data from changing or rolling over in the time between reading or writing the first and second registers.

For the CCS compiler, you can use the #byte preprocessor directive to tell it to place a variable at a specific memory address. Look up the correct memory address in the datasheet (the 0x denotes hexadecimal notation):

//put variables at memory location
#byte PR5L=0xF90 //PR5 low byte
#byte PR5H=0xF91 //PR6 high byte

Later in the code, when we want to set the values, we can set it like any other variable:

PR5H = 10000/256;  //take only high bits
PR5L = 10000%256;  //take only low bits

Alternatively, we can also use pointers:

int8* PR5H;
int8* PRHL;
PR5H = 0xF91;
PR5H = 0xF90;
*PR5H = 10000/256; 
*PR5L = 10000%256;