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 support@ccsinfo.com

How to use the NCO module- demo code
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

How to use the NCO module- demo code
PostPosted: Fri Mar 22, 2013 1:03 pm     Reply with quote

I was asked about this privately, so for the record:
The NCO is pretty easy to use, and works fine with 4.141 IMHO.

Using the 16F1509 or its junior partners, here is a brief how-to:
Code:

// NCO / DDS demo prog  appx 1 Hz resolution NCO demo
// compiled v4.141 dep 
// Use external power of 2 freq crystal for precision 1hz res and accuracy
//
#include <16f1509.h>
#include <stdlib.h>
#Fuses INTRC_IO,NOWDT,PUT,NOMCLR,NOPROTECT,NOBROWNOUT,NOIESO
#Fuses NOFCMEN,NOWRT,NOSTVREN,NODEBUG,NOLVP
#use delay( clock=2000000,INTERNAL ) // closest 'free' 2mhz ref

const unsigned int16 NcIcr[10]={20,100,200,500,1000,4000,8000,12000,20000,50000};
//frequency table in ~~ HZ above using INTOSC

main(void){
   unsigned int8 fp=0;   // init the NCO to appx 4khz
   setup_nco(NCO_ENABLED|NCO_OUTPUT|NCO_FIXED_DUTY_MODE|NCO_CLOCK_FOSC,4000);
   while (1){
     delay_ms(3000); // wait 3 seconds
     set_nco_inc_value(NcIcr[fp++]);
     if (fp>9) fp=0;
   }
}

The frequency is only approximate - for accurate frequency generation with Fosc Internal, use scalar correction:

http://www.ccsinfo.com/forum/viewtopic.php?t=50139

As an aside, this program shows the amount of jitter that the Intosc
generates. When set for an increment of 4000, trigger on the positive edge of the NCO out, and zoom in on the negative edge. On 5 different specimens, the jitter with Intosc operation never falls below 400 nsec.

With an external high quality crystal oscillator, the jitter is FAR less.


Last edited by asmboy on Tue Jul 14, 2015 5:06 pm; edited 1 time in total
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Jul 14, 2015 12:49 am     Reply with quote

Hi,
I tested your code using compiler version 5.048 and has many compiling errors.

Code:
"
*** Error 43 "PIC16F509_NCO.c" Line 17(4,9): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 17(10,11): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 17(11,12): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 17(12,13): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 17(13,14): Expecting a declaration
*** Error 28 "PIC16F509_NCO.c" Line 18(15,19): Expecting an identifier
*** Error 43 "PIC16F509_NCO.c" Line 18(20,21): Expecting a declaration
*** Error 27 "PIC16F509_NCO.c" Line 19(34,35): Expression must evaluate to a constant
*** Error 43 "PIC16F509_NCO.c" Line 19(35,36): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 19(36,37): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 20(6,8): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 20(9,10): Expecting a declaration
*** Error 48 "PIC16F509_NCO.c" Line 20(10,12): Expecting a (
*** Error 43 "PIC16F509_NCO.c" Line 20(13,14): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 20(14,15): Expecting a declaration
*** Error 48 "PIC16F509_NCO.c" Line 20(16,18): Expecting a (
*** Error 43 "PIC16F509_NCO.c" Line 20(19,20): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 20(20,21): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 21(4,5): Expecting a declaration
*** Error 43 "PIC16F509_NCO.c" Line 22(1,2): Expecting a declaration
      33 Errors,  0 Warnings.
Build Failed.

"
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Jul 14, 2015 2:50 am     Reply with quote

I used PIC10F322 to test NCO.
Below is a working code tested with the real PIC10F322.
Code:
#include <10F322.h>
#use delay(internal=16000000)

void main()
{
SETUP_ADC(ADC_OFF);
//Fixed Duty Cycle (FDC) mode 100us on and 100us off pin RA2
SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_FIXED_DUTY_MODE|NCO_CLOCK_HFINOSC, 655);
//Pulse Frequency (PF) mode - 150us off and 62.5ns on time
   //NCO clock is HFINTOSC 16MHz and 1 clock period is 1/16000000=62.5ns set by NCO_PULSE_WIDTH_1
   //The pulse may be increased up to 128 clocks when we set NCO_PULSE_WIDTH_128
   //Then we get 8us on time and 142us off time
   //Check 10F322.h file for further details
//SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_128|NCO_CLOCK_HFINOSC, 437);

while(TRUE){
}
}


Here is a link to an Excel file where I calculated the number that have to be loaded in the increment registers of NCO in order to get a specific width for the NCO output rectangular signal:
https://drive.google.com/open?id=0BwXmKaSw75eKbFlqRFZucjhmYzQ
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Jul 14, 2015 3:23 am     Reply with quote

I have question for you, hoping that you may help, because I remeber you are very good.
I use PIC10F322.
I need to turn on and off pin RA0 very precisely in a range 20us-255us and if it possible up to 10ms.. I have a lot of options and functions tested to do that, but I want to use NCO as replacement for Timer0.
If the output would have been RA2, then would have been very easy: just load new numbers in the registers of NCO and that’s all.
If the output would have been RA1 then I could redirect the RA2 signal with the help of CLC gates to RA1.
But I must use RA0.
Then I was thinking to use NCO as counter-“timer“ and generate an internal interrupt. In the interrupt subroutine I toggle the pin RA0 and load new numbers in NCO registers NCO1INCH and NCO1INCL. Of course in CCS there is only one number.

Here is the code tested, which generates only 150us on and 150 us off on RA0, and not 150us/100us as I would like:

Code:
#include <10F322.h>
#device ADC=16
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A2,PIN_A0 )

void main()
{
SETUP_ADC(ADC_OFF);
SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 437);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(PERIPH);
ENABLE_INTERRUPTS(INT_NCO1);

while(TRUE){
}
}

#INT_NCO1
void NCO_ISR(){
OUTPUT_TOGGLE(PIN_A0);
if (PIN_A0)
   SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 437);
if (!PIN_A0)
   SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1||NCO_CLOCK_HFINOSC, 655);

clear_interrupt(INT_NCO1);
}


There is a problem. The interrupt subroutine is executed, RA0 is toggled, but only the first NCO setup from interrupt subroutine is executed, given the same width for “0” and “1” of the RA0 signal.
Could be because the setup of NCO takes too long? Or are other registers affected?
Is not clear for me why I cannot get “on” and “off” for RA0 with different width.
Any idea how to accomplish that using NCO as “timer” with its internal interrupt?
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Jul 14, 2015 9:49 am     Reply with quote

Dear VICKI2000

Let me politely point out that the demo file is for the
16F1509 NOT 16f509

your errors say :
Quote:

"PIC16F509_NCO.


The 16F509 HAS NO NCO CIRCUITS my friend.......
so of course you get an error.

ALSO i have not done any testing with the #INT feature you try to deploy
(to unknown purpose) ....
I urge you to try using the right header file and see if you do a bit better ok ????
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Jul 14, 2015 10:04 am     Reply with quote

and as to your problem with the NCO_INT

what does your .LST file show being generated?

did you note that you DON'T have to explicitly clear
the int flag as CCS does it for you ?

and think about this:
with a 16mhz INTOSC setting - each clock I-cycle is 250nSec
so there are only 10 I-clocks available for everything
you need to do for making a 25usec output pulse.
View the list file !!!
The interrupt enter/exit overhead alone uses more than 10 cycles ........
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Jul 14, 2015 2:22 pm     Reply with quote

16F1509 indeed and not 16f509, was clear a mistake.
So I tried again with 16F1509 and unfortunately I still got errors:
https://drive.google.com/file/d/0BwXmKaSw75eKVkZacHN4Ym1WYWc

Code:
*** Error 36 "NCO_16F1509.c" Line 11(80,81): Expecting a ; or ,
*** Error 43 "NCO_16F1509.c" Line 14(5,6): Expecting a declaration
*** Error 81 "NCO_16F1509.c" Line 14(10,11): Expecting a basic type
*** Error 28 "NCO_16F1509.c" Line 16(14,26): Expecting an identifier
*** Error 43 "NCO_16F1509.c" Line 16(26,37): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(36,37): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(37,57): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(56,57): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(57,72): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(71,72): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(72,76): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(76,77): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 16(77,78): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 17(4,9): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 17(10,11): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 17(11,12): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 17(12,13): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 17(13,14): Expecting a declaration
*** Error 28 "NCO_16F1509.c" Line 18(15,19): Expecting an identifier
*** Error 43 "NCO_16F1509.c" Line 18(20,21): Expecting a declaration
*** Error 27 "NCO_16F1509.c" Line 19(34,35): Expression must evaluate to a constant
*** Error 43 "NCO_16F1509.c" Line 19(35,36): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 19(36,37): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 20(6,8): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 20(9,10): Expecting a declaration
*** Error 48 "NCO_16F1509.c" Line 20(10,12): Expecting a (
*** Error 43 "NCO_16F1509.c" Line 20(13,14): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 20(14,15): Expecting a declaration
*** Error 48 "NCO_16F1509.c" Line 20(16,18): Expecting a (
*** Error 43 "NCO_16F1509.c" Line 20(19,20): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 20(20,21): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 21(4,5): Expecting a declaration
*** Error 43 "NCO_16F1509.c" Line 22(1,2): Expecting a declaration
      33 Errors,  0 Warnings.
Build Failed.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Jul 14, 2015 2:47 pm     Reply with quote

Regarding the other program, I used “#INT_NCO1” because in CCS user manual page 58 (https://www.ccsinfo.com/downloads/ccs_c_manual.pdf) I have seen that should be the way how to call the function when the interrupt of NCO is triggered.
The function and the interrupt work.
My problem is the fast loading of the NCO1INCH and NCO1INCL with new numbers.

In parallel I have tried also another compiler, the XC8 v1.33 PRO with the next code:

Code:
#include <xc.h>
#define _XTAL_FREQ 16000000
#define TONH 18
#define TONL 73
#define TOFFH 1
#define TOFFL 7

__CONFIG(FOSC_INTOSC & MCLRE_OFF & WDTE_OFF & LVP_OFF & CP_OFF & WRT_OFF & PWRTE_OFF & WRT_OFF & BOREN_ON & LPBOR_ON & BORV_LO);

void main(){

OSCCON=0b01110000;
TRISA=0b00001010;
LATA=0b00000000;
ANSELA=0b00000000;
ADCON=0b00100000;
OPTION_REG=0b00000000;
WPUA=0b00000000;
INTCON=0b11000000;
PIE1=0b00010000;
PIR1=0b00000000;

NCO1INCH = 18;
NCO1INCL = 73;

NCO1CLK = 0b00000010;
NCO1CON = 0b11100001;

while(1){
}
}
void interrupt NCO_Delay(){
    LATA0=!LATA0;
    if (LATA0){
        NCO1INCH = TONH;
        NCO1INCL = TONL;
    }
    if (!LATA0){
        NCO1INCH = TOFFH;
        NCO1INCL = TOFFL;
    }
    NCO1ACC=0;
    NCO1IF=0;
}


The above code produces 20us on and 245.5us off at RA0 seen on oscilloscope.
The precision obtained is 0.4-0.5us in the range 20us-255us on/off, then 4us for 1000us on/off and 40us for 10ms on/off when I change the numbers for TONH, TONL, TOFFH, TOFFL.
The entire interrupt subroutine introduce a delay of around 6us measured on oscilloscope. It is a constant error delay, which was easy corrected with new calculations for NCO increment registers:
https://drive.google.com/open?id=0BwXmKaSw75eKYTQ1MW80QW5MVk0
I would like to implement the same code with CCS C compiler.
What I try to accomplish is the usage of NCO interrupt to generate precise timing/delay as for example to toggle RA0 pin with different width for on and for off.

How can I load fast and simple in the NCO1INCH and NCO1INCL new numbers in NCO interrupt subroutine?

Maybe something like this works:
Code:
#include <10F322.h>
#device ADC=16
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A2,PIN_A0 )

void main()
{
SETUP_ADC(ADC_OFF);
SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 437);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(PERIPH);
ENABLE_INTERRUPTS(INT_NCO1);

while(TRUE){
}
}

#INT_NCO1
void NCO_ISR(){
OUTPUT_TOGGLE(PIN_A0);
if (PIN_A0)
   set_nco_inc_value(437);
if (!PIN_A0)
   set_nco_inc_value(655);
set_nco_accumulator(0);
clear_interrupt(INT_NCO1);
}


I have to try it tomorrow.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Jul 14, 2015 5:12 pm     Reply with quote

the posted demo program still compiles in 4.141

I found that it requires a semicolon at the end of line #7
for my version 5.042
it now compiles and runs as expected with that later version too.
-------------------------
lastly re your program :

I am glad that you have an output you find useful.

have you noticed the amount of JITTER on your
20/245us transititon waveform??
&&
are you pleased with it ?

BTW: this

if (!PIN_A0)

can be replaced with THIS

ELSE

and save some cycles
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Jul 14, 2015 5:53 pm     Reply with quote

and then this.
a seriously excellent programmer aka PCM_Programmer pointed this out to me:

when you wrote:

if (PIN_A0)
that is NOT going to work as you expect,
as you are just asking if a DEFINED CONSTANT compiler value (PIN_A0)
is true which unless it is defined as zero - it always is and will be.

what you want to code to detect an I/O pin change is
if (input(PIN_A0))
........
ELSE
........
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Jul 15, 2015 2:08 am     Reply with quote

1) I tried one more time your first code and surprise, was compiled correctly without errors. I do not know why I got errors 2nd time. Here is the proof:
https://drive.google.com/file/d/0BwXmKaSw75eKQnpidkduNTBzb1k/view?pli=1
2) During my first trials I used „else“ for the second side as you suggested, but due to the other errors encountered I thought that “if()” may take different execution time than “else” and then the “off” and “on” are not as calculated. I was thinking that if I write the same instructions “if()” for “on” and “off”, in order to introduce the same delay, then it would be more precise relation between calculated values “on” and “off” and the measured rectangular signal. But now, after the XC8 code is working, I tried also with “else” as you pointed and works without any detectable additional delays/errors.
Regarding the jitter:
- Comes directly from RC internal oscillator, page 168 of the datasheet indicate +/-3% at 16MHz
http://ww1.microchip.com/downloads/en/DeviceDoc/40001585B.pdf
https://drive.google.com/open?id=0BwXmKaSw75eKZk5hcFFEQS01OGs
- I measured it directly on one PIC10F322 and I found when I have for example on=20us and off=255us programmed, then the real output is on=19.6-20us and off=254.4-254.8us, so the jitter is 0.4us. And that applies for any numbers used for “on” and “off” in the range 20us-255us. I do not think there is any other way to improve that no matter what and how the code is written as long as is related with the clock source which is RC internal.
- The spread of error obtained in precision of “on”/”off” signal is in fact wider up to 3% as datasheet mentions, when we consider different other manufactured PIC10F322 chips.
- Unfortunately I cannot use an external clock source this time, so I have to live with the internal RC.

3) Coming back to CCS code, I tried your suggestions with next code:
Code:
#include <10F322.h>
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A2,PIN_A0 )

void main()
{
SETUP_ADC(ADC_OFF);
SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 437);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(PERIPH);
ENABLE_INTERRUPTS(INT_NCO1);

while(TRUE){
}
}

#INT_NCO1
void NCO_ISR(){
OUTPUT_TOGGLE(PIN_A0);
if (input(PIN_A0))
   set_nco_inc_value(655);
else
   set_nco_inc_value(437);
set_nco_accumulator(0);
clear_interrupt(INT_NCO1);
}

Unfortunately is not working as expected.
The RA0 pin is toggled “on” and “off”, but the width of the signal does not change. I got the same width for “on” as for “off” and equal with what is set in the beginning by “SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 437);”

The similar XC8 program works without problems.
Any ideas how to debug the CCS code?
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Jul 15, 2015 3:33 am     Reply with quote

Here are the last updates, not very promising.
The code below is working:
Code:
#include <10F322.h>
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A2,PIN_A0 )

void main()
{

SETUP_ADC(ADC_OFF);
SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 762);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(PERIPH);
ENABLE_INTERRUPTS(INT_NCO1);

while(TRUE){
}
}

#INT_NCO1
void NCO_ISR(){
OUTPUT_TOGGLE(PIN_A0);
if (input(PIN_A0))
   SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 762);
else
   SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 482);
set_nco_accumulator(0);
clear_interrupt(INT_NCO1);
}

But, the NCO interrupt subroutine takes around 14us, so new numbers had to be calculated. That would not be a problem because is a deterministic constant error. The problem is the jitter 2us. With the above numbers I get 100us for “on” and 150us for “off”, but in fact is 98-100us for “on” and 148-150us for “off”.
The code is 19%RAM and 23%ROM, not so good compared with XC8 which is 6.2%RAM and 10.9%ROM.
It seems like “set_nco_inc_value()” function does not really work.
I found the “set_nco_inc_value()” and “set_nco_accumulator()” functions inside to “10F322.h”.

A proper debug to find the cause of the jitter 2us compared with XC8 0.5us and what is happening with “set_nco_inc_value()” function will be helpful.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Jul 15, 2015 5:13 am     Reply with quote

I used one more time next code:
Code:
#include <10F322.h>
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A2,PIN_A0 )

void main()
{
SETUP_ADC(ADC_OFF);
SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 437);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(PERIPH);
ENABLE_INTERRUPTS(INT_NCO1);

while(TRUE){
}
}

#INT_NCO1
void NCO_ISR(){
OUTPUT_TOGGLE(PIN_A0);
if (input(PIN_A0))
   set_nco_inc_value(655);
else
   set_nco_inc_value(437);
set_nco_accumulator(0);
clear_interrupt(INT_NCO1);
}

Then I tried to follow your suggestion and to look at the .lst file, even if I am not and ASM boy.
Here are the LST files:
1) The code written in CCS IDE:
https://drive.google.com/open?id=0BwXmKaSw75eKMjc4SUoxd1prbmM
I cannot understand easy the registers in line with assembly instructions, so I used also MPLABX with CCS complier:
2) The same code as above written in MPLABX with CCS C compiler:
https://drive.google.com/open?id=0BwXmKaSw75eKeVdhelZyazdUMWc
Now I see the name of the registers instead of numbers in line with assembly instructions.
3) The working code written in MPLAX with XC8 compiler:
https://drive.google.com/open?id=0BwXmKaSw75eKN05GcDl3SmFEaUE
Not only that the code is a lot longer in CCS, but I see some differences between assembly instructions in different blocks. For example when I reset the NCO accumulator the CCS resets only NCO1ACCU and NCO1ACCH, but there is one more named NCO1ACCL, which XC8 clear loads it with 0 using CLRF instruction. Maybe I do not understand it right, but CCS seems to CLRF the PWM register for high bits CLRF PWM2DCH instead of CLRF NCO1ACCL.
I do not know if the rest of the code is right, but that seemed obviously to me.
Do you see anything else which might be wrong?
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Jul 15, 2015 6:47 am     Reply with quote

Finally after some hours, there is light.
I replaced one by one the functions defined in the CCS complier with assembly code inspired from LST file of XC8.
The “set_nco_accumulator(0)” function was replaced with:
Code:
#asm
   CLRF NCO1ACCL
   CLRF NCO1ACCH
   CLRF NCO1ACCU
#endasm

The 2us jitter was reduced to lower normal values of the internal RC oscillator after NCO1ACCL was cleared too. So, it seems a bug in CCCS “set_nco_accumulator(0)” function.
Then slowly, one by one I replaced with assembly all the C code from NCO interrupt.
Here is the working code, now with only 0.4us jitter, working similar as XC8 code.
The NCO interrupt subroutine takes around 5us, so I had to recalculate the numbers loaded in NCO1INCH and NCO1INCL registers.
The mapping for internal registers I found it in the datasheet of PIC10F322 page 14:
http://ww1.microchip.com/downloads/en/DeviceDoc/40001585B.pdf

Code:
#define LATA 0x07
#define NCO1ACCL 0x27
#define NCO1ACCH 0x28
#define NCO1ACCU 0x29
#define NCO1INCH 0x2B
#define NCO1INCL 0x2A
#define PIR1 0x0C


Here is full working code:
Code:
#include <10F322.h>
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A2,PIN_A0 )

#define LATA 0x07
#define NCO1ACCL 0x27
#define NCO1ACCH 0x28
#define NCO1ACCU 0x29
#define NCO1INCH 0x2B
#define NCO1INCL 0x2A
#define PIR1 0x0C

void main()
{

SETUP_ADC(ADC_OFF);
SETUP_NCO(NCO_ENABLED|NCO_OUTPUT|NCO_ACTIVE_LOW|NCO_PULSE_FREQ_MODE|NCO_PULSE_WIDTH_1|NCO_CLOCK_HFINOSC, 736);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(PERIPH);
ENABLE_INTERRUPTS(INT_NCO1);

while(TRUE){
}
}

#INT_NCO1
void NCO_ISR(){
//OUTPUT_TOGGLE(PIN_A0);
#asm
   MOVLW 0x01
   XORWF LATA, F
#endasm
if (input(PIN_A0)){
//   set_nco_inc_value(736);
#asm
   MOVLW 2
   MOVWF NCO1INCH
   MOVLW 224
   MOVWF NCO1INCL
#endasm
}
else{
//   set_nco_inc_value(471);
#asm
   MOVLW 1
   MOVWF NCO1INCH
   MOVLW 215
   MOVWF NCO1INCL
#endasm
}
// set_nco_accumulator(0);
#asm
   CLRF NCO1ACCL
   CLRF NCO1ACCH
   CLRF NCO1ACCU
#endasm
//clear_interrupt(INT_NCO1);
#asm
   BCF PIR1, 0x4
#endasm
}


I used my Excel sheet to make the 5us correction:
https://drive.google.com/file/d/0BwXmKaSw75eKYTQ1MW80QW5MVk0
The memory used is 19%RAM and 20%ROM, still double than XC8.
Maybe with a little bit more effort in setting up the PIC and interrupts, I could write it completely in ASM, even if it is not my specialty.
Here is an NCO ASM code written by somebody else on another forum for PIC16F1503, but was mentioned that might work/be adapted for PIC10F322:
https://drive.google.com/file/d/0BwXmKaSw75eKQjFmbWdyX2k3RFE
I think combined with the CCS code above may produce a smaller code with less RAM and ROM.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Jul 15, 2015 8:03 am     Reply with quote

This is some first rate self help.
Congratulations!!
Now you see why i asked you to focus on the jitter.

The main source of the excess instability is the process of jamming the
NCO register .
You are fortunately writing them in assembler in the correct order
per datasheet 20.1.4
BUT
the instability of doing it in CCS can very well be traced to excess overhead and only marginal time when NOT in the foreground code execution during a 5 us cycle.

You are bound to be spending almost 100% of your time in the ISR in reality.
And the ASM code just buys you some extra I-Cycles. ( that happen to be enough to smooth out the jitter)

if you DON't have a lot of other stuff to do - ie this is JUST a signal generator,
You might profitable code this as a TIGHT flag polling loop in MAIN() that watches the NCO INT FLAG ( with no interrupt at all) - and does what the ISR does , and explicitly clearing the NCO OVF flag at the end of the polling-handler code each time the flag is set.
The time spent testing the flag and finding it FALSE in a MAIN() polling loop will be far less than the entry setup code for the ISR as you use it now.

That should reduce jitter to the minimum value of the intosc source.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 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