dsPIC30F4011 Examples

This page presents useful information on writing C programs for the dsPIC30F4011, including:

  • What software to install.
  • How to connect the PICkit 2 to the dsPIC30F4011.
  • How to compile a C program for dsPIC30F4011 and download it onto the chip using the PICkit 2 application.
  • Short examples of several dsPIC30F4011 features, including analog input, timers, serial i/o, etc.
  • A “super example”, which combines various functionality into a single longer example.

What software to install

Most people use MPLAB to develop programs for the dsPIC30F4011. However, having experienced persistent problems after upgrading from version 8.x to MPLAB X, I have now completely abandoned it. Instead, I use a plain text editor to write my C programs, Microchip’s XC16 compiler to build them, and the PICkit 2 software application to download the compiled hex files onto the dsPIC. This is the approach that I use and that I recommend to others. The process described below is Windows-specific.

I have always thought that the process of creating new programs in MPLAB was insanely complicated. I just don’t see the merit of creating a “project” and “workspace” with all kinds of mysterious files and subdirectories just to compile what (in my case at least) is invariably a single C file. The approach described below does away with all this – just place your C program (a single C file) in its own directory and compile it to produce a hex file – that’s it.

What to install:

  1. The Notepad++ text editor, which is free and provides many useful features. Notepad++ is a great piece of software that I use all the time. However, you could use just about any plain text editor, including Notepad which is provided in Windows.
  2. The XC16 C compiler, which is available for free from microchip.com. The download is about 120 MB in size.
  3. The PICkit 2 application, which can also be downloaded free of charge from microchip.com.

Connecting the PICkit 2 to the dsPIC30F4011

Here’s a simple circuit to get the dsPIC up and running with the PICkit 2 on a breadboard:

Diagram of basic circuit for connecting PICkit 2 to dsPIC30F4011

A simple example program

Here’s a simple example program to blink the LED on pin RD0 in the circuit shown above:

//
// dsPIC30F4011 example - blink an LED on RD0
// Written by Ted Burke, Last updated 6-3-2013
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int main(void)
{
	// Make RD0 a digital output
	_TRISD0 = 0;
	
	// Blink LED on RD0
	while(1)
	{
		_LATD0 = 1;
		__delay32(15000000);
		_LATD0 = 0;
		__delay32(15000000);
	}
}

I create a new folder for every dsPIC program I write. For this example, I will assume the above code is saved as “main.c” in the folder “D:\blink\”. To compile this program, I use a simple build script, which saves me from typing in the unwieldy compiler command directly. I use the exact same 2-line build script (shown below) for every dsPIC30F4011 program. Save the lines below into a file called “build.bat” in the same folder as “main.c”

xc16-gcc main.c -mcpu=30F4011 -Wl,--script=p30F4011.gld
if errorlevel 0 xc16-bin2hex a.out

At this point the program folder should contain two files:

Screenshot of program folder containing files main.c and build.bat

To run the build script, open a console window, navigate to the folder where your program files are located, and type the following command:

build.bat

Here’s what that looks like in my console window:

Screenshot of console where build.bat has been run

Assuming that the C program compiles without errors, two new files will be added to the directory, “a.out” and “a.hex”. The latter file is the one that will be transferred to flash memory on the dsPIC using the PICkit 2 application.

Screenshot of program folder containing two additional files - a.out and a.hex

Make sure that the PICkit 2 is connected to the dsPIC circuit, and then launch the PICkit 2 application:

PICkit 2 application screenshot

Assuming the PICkit 2 is correctly connected to the circuit, the message circled in red above should be visible: “PICkit 2 found and connected. PIC Device Found.”

To download the hex file onto the dsPIC, click the “Auto Import Hex + Write Device” button (circled in blue above) and browse to find the file “a.hex” in the same directory as “main.c”. Once “a.hex” is selected the download process should begin. After a few seconds you should see the “Programming Successful” message circled in red below.

Screenshot of the PICkit 2 application showing the "Programming Successful" message

To actually run the program on the dsPIC, you may need to tick the VDD check box (circled in blue above) to supply power to the circuit. If all is well, the LED should start blinking.

Digital i/o

This program uses one digital output (RD0) and one digital input (RD1). When RD1 is high, an LED on RD0 blinks fast; when RD1 is low, the LED blinks slow.

The function __delay32() (defined in “libpic30.h”) creates a delay of the specified number of instruction cycles. In this example, the dsPIC is running at 30 MIPS (million instructions per second) so, for example, “__delay32(15000000)” creates a delay of half a second. The number “32” in the function name refers to the fact the that specified number of instruction cycles is a 32 bit unsigned value, allowing very long delays to be generated with a single call.

The same build script as for the simple example above should be used.

//
// dsPIC30F4011 example - blink an LED fast or slow
// Written by Ted Burke, Last updated 6-3-2013
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

int main(void)
{
	// Make RD0 a digital output
	_TRISD0 = 0;
	
	// Make RD1 a digital input
	_TRISD1 = 1;
	
	// Blink LED on RD0
	while(1)
	{
		// Toggle RD0 (turn LED on or off)
		_LATD0 = 1 - _LATD0;
		
		// Either delay for 0.1 or 0.5 seconds
		if (_RD1 == 0) __delay32(3000000); // 0.1 second delay
		else __delay32(15000000); // 0.5 second delay
	}
}

Analog input

//
// dsPIC30F4011 example - read an analog input
// Written by Ted Burke, Last updated 6-3-2013
//

#include <xc.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

unsigned int read_analog_channel(int channel);

int main(void)
{
	int voltage;
	
	// Make RD0 a digital output
	_TRISD0 = 0;
		
	// Configure AN0-AN8 as analog inputs
	ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
	ADCON1bits.ADON = 1;   // Turn ADC ON

	// Blink LED on RD0
	while(1)
	{
		// Toggle RD0 (turn LED on or off)
		_LATD0 = 1 - _LATD0;
		
		// Length of delay depends on AN0 pin voltage
		voltage = read_analog_channel(0);
		__delay32(voltage * 30000L);
	}
}

// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
unsigned int read_analog_channel(int channel)
{
	ADCHS = channel;          // Select the requested channel
	ADCON1bits.SAMP = 1;      // Start sampling
	__delay32(30);            // 1us delay @ 30 MIPS
	ADCON1bits.SAMP = 0;      // Start Converting
	while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
	return ADCBUF0;
}

Serial output

TO BE WRITTEN

Serial input

TO BE WRITTEN

Using a timer

TO BE WRITTEN

Using a timer interrupt

TO BE WRITTEN

Pulse Width Modulation

TO BE WRITTEN

dsPIC30F4011 Super Example

This is my dsPIC30F4011 “super example”. When I’m writing a program for this handy microcontroller, I often use this template code as my starting point and trim out whatever I don’t need.

This example includes the following features (further details below):

  • Digital output
  • Analog input
  • PWM output
  • Serial output via UART
  • Serial input via UART
  • Timer 1 interrupt
//
// dsPIC30F4011 Super Example
// Written by Ted Burke
// Last updated 27-8-2012
//
// Featuring digital i/o, analog input,
// PWM output, UART Tx/Rx, Timer 1 ISR.
//

#include <xc.h>
#include <stdio.h>
#include <libpic30.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

// Function prototypes
void setup();
unsigned int read_analog_channel(int n);

// Function prototype for Timer 1 interrupt service routine
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void);

int main()
{
	int voltage;
	char c;

	// Set up digital i/o, analog input, PWM, UART and interrupt
	setup();

	while(1)
	{
		// Read a voltage from AN0 and print it via serial port
		voltage = read_analog_channel(0);
		printf("Voltage = %d\r\n", voltage);

		// Toggle LED on RD0
		_LATD0 = 1 - _LATD0;

		// Check if any characters were received via UART
		if (U1STAbits.URXDA == 1)
		{
			c = U1RXREG;
			if (c == '2') _LATD2 = 1 - _LATD2;
			if (c == '3') _LATD3 = 1 - _LATD3;
		}

		__delay32(6000000); // 200ms delay
	}

	return 0;
}

// Timer 1 interrupt service routine
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
{
	// Clear Timer 1 interrupt flag
	IFS0bits.T1IF = 0;

	// Toggle LED on RD1
	_LATD1 = 1 - _LATD1;
}

// This function sets up digital i/o, analog input,
// PWM, UART and timer interrupt.
void setup()
{
	// Configure all 4 port D pins as digital outputs
	TRISD = 0;

	// Configure AN0-AN8 as analog inputs
	ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
	ADCON1bits.ADON = 1;   // Turn ADC ON

	// Configure PWM for free running mode
	//
	//   PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * PTPER
	//   PWM pulse width = (Tcy/2) * prescale * PDCx
	//
	PWMCON1 = 0x00FF;     // Enable all PWM pairs in complementary mode
	PTCONbits.PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
	PTPER = 9375;         // 20ms PWM period (15-bit period value)
	PDC1 = 1406;          // 1.5ms pulse width on PWM channel 1
	PDC2 = 1406;          // 1.5ms pulse width on PWM channel 2
	PDC3 = 1406;          // 1.5ms pulse width on PWM channel 3
	PTMR = 0;             // Clear 15-bit PWM timer counter
	PTCONbits.PTEN = 1;   // Enable PWM time base

	// Setup UART
	U1BRG = 48;            // 38400 baud @ 30 MIPS
	U1MODEbits.UARTEN = 1; // Enable UART

	// Configure Timer 1
	// In this example, I'm setting PR1 and TCKPS for 8Hz
	PR1 = 14648;          // Set the Timer 1 period (max 65535)
	TMR1 = 0;             // Reset Timer 1 counter
	IEC0bits.T1IE = 1;    // Enable Timer 1 interrupt
	T1CONbits.TCKPS = 3;  // Prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
	T1CONbits.TON = 1;    // Turn on Timer 1
}

// This function reads a single sample from the specified
// analog input. It should take less than 5us when the
// microcontroller is running at 30 MIPS.
// The dsPIC30F4011 has a 10-bit ADC, so the value
// returned is between 0 and 1023 inclusive.
unsigned int read_analog_channel(int channel)
{
	ADCHS = channel;          // Select the requested channel
	ADCON1bits.SAMP = 1;      // Start sampling
	__delay32(30);            // 1us delay @ 30 MIPS
	ADCON1bits.SAMP = 0;      // Start Converting
	while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
	return ADCBUF0;
}

This code is written for Microchip’s XC16 compiler (xc16-gcc.exe). You can compile it in MPLAB X, but personally I’ve been having a lot of reliability problems with the IDE, so I’m currently just using a plain text editor (Notepad++) to edit my programs and a simple makefile to manage the build process with XC16. I use the (very useful) PICkit2 helper application to transfer my compiled hex file to the dsPIC chip. To be honest, I’m finding this way of working way more convenient than using MPLAB X, which takes forever to start on my laptop and really just doesn’t run all that well. By comparison, Notepad++ / XC16 / PICkit2 all run really smoothly and aren’t giving me any reliability problems. I’m not using a debugger at all – I just use printf a lot!

Here’s my makefile:

MP_CC_DIR="D:\Program Files\Microchip\xc16\v1.00\bin"
MP_CC="D:\Program Files\Microchip\xc16\v1.00\bin\xc16-gcc.exe"

all: super.hex

super.cof: main.c
	$(MP_CC) main.c -o super.cof -mcpu=30F4011 -Wall -Wl,--script=p30F4011.gld

super.hex: super.cof
	$(MP_CC_DIR)\\xc16-bin2hex super.cof -a -omf=elf

If you want something even simpler (I always want something simpler!) you can try the following build script. If you don’t have make installed, this will be easier to use than the Makefile above. Assuming you have XC16 installed, just save the following into a file called “build.bat” in the same folder as your “main.c” file. To run it, open a command window, move to the folder where your main.c file is located and type “build”. It should create a file called “a.hex” which is ready to be programmed onto the dsPIC (for example using the PICkit 2 application).

xc16-gcc main.c -mcpu=30F4011 -Wl,--script=p30F4011.gld
if errorlevel 0 xc16-bin2hex a.out

153 Responses to dsPIC30F4011 Examples

  1. george skep says:

    Dear mr.Ted,
    We tested today at the lab the source code you sent me and worked fine.We made the adjustments with the delay to be set at 0
    _LATD0 = 1;
    __delay32(00000000);
    _LATD0 = 0;
    __delay32(00000000) in order to see better pulse at oscillator.I would like to know the purpose of this delay.We also added deadtime so we dont have problem with mosfets.Now the final adjustment we want to make is add a potentiometer to AN1 so that we can adjust the voltage but keep the frequency constant at 50hz as you did.So if you could send me this addon will be great!
    The frequency of the sinusoid we want to produce is 50Hz as you choose.
    The frequency for the PWM signal for the mosfet must be 20-50 KHZ.The maximum and minimum duty cycles must be 0-100 %.
    The next step is to test the whole circuit on breadboard.You will hear our news soon!!
    Thanks a lot in advance mr.Ted!

  2. Imad says:

    Dear Mr. Burke,
    Im really new to coding and i have to write a code for generating two PWM signals with variable phase shift using DSPIC30F4011. Im trying to do that but its kind of difficult and takes time. Your Help is highly appreciated.
    Thanks in advance

    • batchloaf says:

      Hi Imad,
      If you can give me more details on the waveforms you wish to produce, I’ll try to help. The kind of details I need to know include the following:

      1. Do you need to vary the frequency of the PWM signals or is the frequency constant?
      2. Do you need to vary the duty cycle (i.e. pulse width) of the PWM signals or is it constant?
      3. If you do need to vary the duty cycle, will the value be the same for both waveforms or could they be different from each other?
      4. Do you need the dsPIC to do anything other than generating the PWM waveforms? If this is the only thing that the microcontroller needs to do, the solution can be quite simple. However, if (as is usually the case) the microcontroller needs to be doing other things at the same time (reading sensors, etc) then a little more coding will be required.

      I’ll be going away for a few days on Monday, so if I don’t respond quickly that’s probably why.

  3. Imad says:

    The details of the generated 2 PWM signals are:
    1- Both have the same frequency (10 KHz) and constant
    2- Duty Cycle/Ratio for both of them is 50%, and this is constant
    3- lets say the first PWM has no phase shift, and only phase shifting the second one ( so variable phase shift).

    To summarise the purpose of the 2 PWM, i need them to trigger 2 MOSFETs switches, so the PWM is required for DC circuit

    • batchloaf says:

      Hi Imad,

      Sorry for the delay in responding – I’ve just returned from holidays. I have a couple more questions before I can prepare an example:

      1.) What is the minimum and maximum required phase shift between the first and second waveform?

      2.) What will be controlling the variation of the phase shift? Would it be relevant if I create an example program where the phase shift is controlled by an analog voltage on (e.g. from a potentiometer) connected to one of the dsPIC’s analog input pins?

      Regards,
      Ted

  4. Imad says:

    Hi Ted,
    Its fine, hope you had a good holidays. The phase shift should vary from zero to 180 phase shift. And it can be controlled either by potentiometer, or just changing the phase shift value on the code and update the code on the chip and check the results.
    Thank you for you time.

    Regards,
    Imad

  5. swetha says:

    Im going to design a dc energymeter using dspic30f..
    im new to do this..
    to create 1sec delay using timer..what to do?actually i want to take 10samples in a sec..so have to check whether 1sec reach or not

  6. nand says:

    hi
    i liked d posts..the help is appreciable. i have been working on dsPIC30F4011 for finding the phase shift between two sine waves but i’m not able to get the output..could you please help me on that

    • batchloaf says:

      Hi Nand,

      Can you give me some more details of your application please? Where are the sine waves coming from? What amplitude and frequency are they? If you can provide a bit more information, I’ll sketch out some simple example code.

      Ted

      • nand says:

        hai ted
        sorry for the late reply.i’m giving the sine waves from the clamper circuit after measuring using current transducer and voltage transducer, from the transmission line after measuring using current transducer and voltage transducer from the transmission line.the sine waves are of 0-5v magnitude with 50hz freq.

  7. nand says:

    thank u in advance Ted

  8. nand says:

    Hi Ted
    Thank u very much.I tried with that. I”m using MPLAB so i got some problems of memory . i corrected that by giving heap value. since I have to calculate the reactive power,with phase difference I need magnitudes of both signals. how to include that in this program?

    Thank u in advance Ted

    Nand

  9. heera says:

    Dear Mr.Ted,
    Iam using a dsPIC 30F4011 to generate gate pulses for a MOSFET. The MOSFET switch is connected in parallel to a solar panel. The current sensor connected in series with the switch wil sense the current output and is connected to the ADC input of the same dsPIC. My program should be such that only when the gate pulse goes high the ADC should sample the sensor output. But Iam having difficulty in configuring the ADC to respond to an external trigger for start of module.(my gate pulse in this case)

  10. batchloaf says:

    Hi Heera,

    I’m confused. If your dsPIC is generating the gate pulses, can you not just include in your program to read the ADC after the gate pulse has been initiated?

    For example (I’m just making up the gate pulse duration and frequency),

    while(1)
    {
        _LATD0 = 1; // begin gate pulse
        __delay32(30000); // 1ms delay
        current = read_analog_channel(0); // measure current
        __delay32(120000); // 4ms delay
        _LATD0 = 0; // end gate pulse
        __delay32(300000); // 10ms delay
    }
    

    …or something like that?

    Is the problem that you are using PWM or some other hardware feature of the dsPIC to generate the gate pulses? If so, please give me some more details about the gate pulse signal (is it periodic? what is the frequency? what is the pulse width? how long after the start of the gate pulse should the ADC be read? etc) and I’ll try to come up with an example program.

    Ted

  11. heera says:

    Hi Ted,
    My gate signal has a time period of 2 seconds and an on time of 1ms. I want the ADC to sample and convert just once at the rising edge of the gate pulse. I had written a simple ADC sub routine as u have done but the value in my buffer is wrong. Should I use input capture to trigger the ADC at the rising edge?.

    • batchloaf says:

      Hi Heera,

      Since the time of the analog sampling is entirely predictable, there’s no need to use input capture to trigger it. It’s not that it wouldn’t work, but you would only be detecting the occurrence of an event that you are initiating yourself! It seems to me that it would be much simpler to use an interrupt to generate the gate pulses at a regular interval (2 seconds) and include the analog sampling in the same interrupt service routine that generates the gate pulse.

      Unfortunately, I’m running out the door as I type this, so I can’t do any sample code now, but I will write a simple example when I get a chance, so that you can compare it with how you did it. Perhaps that will help.

      By the way, are you sure you want to read the analog sample exactly at the rising edge of the gate pulse? Shouldn’t you leave a short delay after the start of the pulse to let the current reach its steady state value? Or are you measuring a different current?

      Ted

  12. Andrew says:

    Hello Ted, I was thinking if you have any signal processing example with dspic, for example a simple filter without the dspicFD tool. Thanks by now! Andrew

  13. Andrew says:

    Perfect!! Very kind of you!! I’ll be waiting here!! See you!!

  14. Song says:

    Dear Mr.Ted,
    I would like to thank you for your example,it’s very useful for me. I’m working on dsPIC30F4011 for the Variable Frequency using signal Generation (as Direct Digital Synthesis (DDS) or Digital Control Oscillator (DCO)). Do you have any ideal,advice or simple example for the signal generation (as DCO or DDS)?

    Thank you so much.
    Regards,
    Song

    • batchloaf says:

      Hi Song,

      Thanks, I’m glad you found my example useful.

      My understanding is that DDS usually uses a digital-to-analog converter (which is not included within the dsPIC30F4011) and that DCO uses a separate analog oscillator that is under the control of the microcontroller. I haven’t implemented either on the dsPIC, but I’m sure they wouldn’t be too difficult to do.

      What I have done is use the PWM output of the dsPIC to generate a sinusoidal waveform. By adding a lowpass RC filter to the PWM output, you can easily turn that into a regular sinusoidal waveform. The resolution and frequency will be limited by the clock speed of the dsPIC and the resolution of the PWM duty cycle, but perhaps that won’t be a problem in your chosen application. What kind of frequencies are you looking to generate? If it’s within the appropriate frequency range for the PWM approach, perhaps I can post a simple example program.

      Ted

    • batchloaf says:

      By the way, I assume you’re trying to generate sinusoidal waveforms? Please specify if that’s not the case.

  15. Song says:

    Hi Ted,
    Thank you for your reply,

    Actuary, I’m trying to generate the PWM by the digital instead the analog to control the inverter by Variable Frequency Control. I found some example used the DDS to generate the waveform as Sinusoidal and Square wave. So,I think the DDS technique may be work in this case.

    Thank you so much.
    Regards,
    Song

  16. Song says:

    Dear Ted,
    How are you?

    I’ve seen your the other example in PWM Generating. They make me understand, but I’ve some questions.(I’ve been learning the dsPIC30F4011 for 3 weeks.)

    1. In the example “IGBT control in a buck-boost DC-DC converter” you used the OC1-OC4 to generate the square wave to control IGBT. But in example “PWM output on 2 channels of the dsPIC30F4011 with equal duty cycle and 180 degrees out of phase” you used PWM Module to generate the PWM signal. For the two example, what is difference between using the OC1-OC4 and PWM Module?

    2. In example “IGBT”, the PR2 was set to 20kHz (PR2 = 1500), because the Fcy = 30MHz,right? If the Fcy is not 30MHz (maybe Lower or Higher), the PR2 will be changed to another value,right?

    3. For the _delay32(30000000), that’s mean “1 second delay”. “300000000 = 1 second” is upon the “30MIPs” or “Fcy (max)”.

    Sorry for my questions that are annoying you.

    Thank you for your time,
    Regards,
    Song

    • batchloaf says:

      Hi Song,

      Don’t worry, you’re questions aren’t annoying! I’ll do my best to explain:

      1. In many applications, you could use either the output compare (OC) pins or the PWM module. Both are capable of easily generating simple PWM signals, for example. However, there are certain cases where one or other will be easier to use. In both cases a timer which runs in the background drives the generation of the output waveform. Let’s assume, for example, that Timer 2 is being used. The register TMR2 will be counting up from 0 to its maximum value in steps of 1. The speed it counts depends on Fcy and also on the prescaler value that you specify (in the T2CON register, I think). When TMR2 reaches the same value as PR2 (the period register for Timer 2), it resets to zero and starts counting up again. The higher the value of PR2, the longer it takes TMR2 to reach the maximum value and reset to zero. The basic difference between the PWM module and the OC pins is that the PWM module’s pulses always start when TMR2 resets to zero and end when TMR2 reaches the value you specify in PDCx (where x is whichever channel number you’re using), whereas you can specify both the start and stop time of OC pulses on each channel using the OCxR and OCxRS registers respectively. This allows you to create arbitrary phase shifts between OC waveforms with the same period. If you want two PWM signals exactly 180 degrees out of phase, it’s easy enough to do with either OC pins or PWM module. However, if you wanted them (let’s say) 60 degrees out of phase, that’s a completely different story – it would be much easier to do that with the OC pins.

      2. Yes, that’s right. The Timer 2 period is specified in the PR2 register, but it depends on Fcy and also on the timer prescaler (specified in T2CON, I think).

      3. Yes, I set the clock oscillator frequency (Fosc) to 120MHz (the maximum you can get with the internal fast RC oscillator). The dsPIC performs one machine code instruction every four oscillator cycles, so that means it performs 30 million instructions per second (30 MIPS, or Fcy = 30MHz). The time taken to perform one instruction – what we call the instruction cycle, Tcy – is therefore 1/30000000 seconds (i.e. Tcy = 33.33ns). When you implement a delay using the function “__delay32”, the time is specified in instruction cycles. Therefore “__delay32(30000000)” gives you a 1 second delay. By the way, the reason “32” is included in the function name is just to remind us that the number you specify can be a 32-bit integer.

      I hope that helps to clarify things!

      One final thing I’ll say about the output compare pins is that I only recently learned how to use them, but now that I know how I find myself using them more often than the PWM pins. I just find them simpler to use. There are a couple of things about the PWM module that seem unnecessarily complicated to me. By contrast, the OC pins keep things relatively simple.

      Ted

  17. Song says:

    Hi Ted,

    Thank you for your reply. Your explanations are very useful. Now I know, I should use the OC pins in my application, because I think it’s not complicate like PWM Module and easy to set the dead time and duty cycle.

    Thank you so much, You are the great man.
    Regards,
    Song

  18. Song says:

    Hi Ted,

    I have the question again.

    In case of Fcy = 30MHz if the PR2 = 3000, it’s mean PR2 is 10kHz.
    In case of Fcy = 30MHz if the PR2 = 300, it’s mean PR2 is 10MHz.
    In case of Fcy = 15MHz if the PR2 = 3000, it’s mean PR2 is 5kHz.
    In case of Fcy = 15MHz if the PR2 = 300, it’s mean PR2 is 5MHz.
    Is that correct?
    (It’s not calculate from 30 MIPS,right?)

    So I can vary the frequency by vary the value of PR2.

    Thank you so much,again. 🙂
    Regards,
    Song

    • batchloaf says:

      Hi Song,

      Assuming the prescaler ratio is set to 1:1, then the frequencies for the values you specified would be as follows:

      • If Fcy = 30MHz and PR2 = 3000, the PWM frequency is 10 kHz
      • If Fcy = 30MHz and PR2 = 300, the PWM frequency is 100 kHz
      • If Fcy = 15MHz and PR2 = 3000, the PWM frequency is 5 kHz
      • If Fcy = 15MHz and PR2 = 300, the PWM frequency is 50 kHz

      If the prescaler is set to a higher value, that will scale down the frequency, but if you leave it set to 1:1, you’ll get the frequencies listed above.

      Ted

  19. Song says:

    Hi Ted,
    I got it.

    Thank you so much. 🙂
    It’s my lucky that I found you. 🙂
    Regards,
    Song

  20. Christos says:

    Dear Mr Ted
    hello, its now three weeks I am struggling with the programming part of my project. Since I am new in the field of programming I have very little knowledge on how to get started. I would like to know if there is any possibility you can help me overcome the programming bit.
    The general idea of my project is to generate two identical but anti-phase PWM signals as the example you did above. The main difference is that the duty cycle will be generated through a PI controller.
    More precisely, I will use a sensor to measure the output voltage from a PV, this sensor is scaled from 0-2 volts, the information from this has to pass through an ADC and the result from the ADC will be used as the reference value of the PI controller. The output value of the PI controller will determine the duty ratio of the PWM.
    I do have everything working perfectly well in Simulink but I have too many troubles converting all this into real C-programming.
    Please let me know if you can help me. I can tell you all the information needed. Your Help is highly appreciated
    Thanks in advance

    • Christos says:

      I forgot to mention that the programming has to be done using MPLab and the dsPIC
      Thanks Again

    • batchloaf says:

      Hi Christos,

      What is the relationship you need to implement between the 0-2V input signal and the duty cycle? If that voltage is the reference for the controller, what is the voltage that it’s being compared to? Also, what are the minimum and maximum duty cycle values? If the maximum duty cycle value is less than 50%, then it’s actually pretty easy to do what I think you need. If the maximum duty cycle is greater than 50%, it’s a little bit more complicated.

      Basically, if you can explain exactly how the duty cycle is calculated from the input voltage, then I can try to write a really short example program that will get you started.

      It might help if you can show me your simulink model. Can you post it online and include a link in your reply? Is there a particular sampling frequency that I should use for the controller?

      Ted

      • Christos says:

        Hello Mr Ted,
        Thanks for your reply. Basically I have to design a closed loop system between a converter and a PV. The irradiance value will affect the output voltage of the PV and with the help of a PI controller I have t track the maximum power point.
        For the programming part, to measure the irradiance value I use a sensor acting as a PV, it measures the frequency of halogen lamps and converts the frequency into current. It then passes the current through a resistance and converts it into voltage. The output voltage of this sensor can be between 0 and 2 volts. At zero volts it means that it is dark and at 2 volts it means that the light is at its maximum point. The range between 0 and 2 is then transformed into a percentage, with 0 being 0% and 2 being 100%. The output of this sensor is then processed through an analog to digital converter, giving a hexadecimal value corresponding to the percentage value from above.
        The output value of the ADC will be in volts and will represent the reference voltage that a PI controller will use to calculate the duty ratio value. The duty ratio value can be between 0.2-0.8 depending on the irradiance of the lamps to maintain the maximum power point.
        Furthermore, the two PWM signal must always be anti-phase with a constant frequency of 20KHz.

        Thank YOU so much for your time

      • batchloaf says:

        So if the maximum duty cycle is 80%, that means that both PWM outputs can be on at the same time? i.e. The two anti-phase pulses can overlap in time? Is that right?

  21. Christos says:

    Not really. Since they are ant-phase there is a phase shift between them of 180 degrees, hence when the first PWM signal is HIGH the second is LOW

  22. batchloaf says:

    Ok, let’s call the two outputs are A and B. What I think you’re saying is that:

    When the duty cycle of A is 80%, the duty cycle of B is 20%.
    When the duty cycle of A is 60%, the duty cycle of B is 40%.
    When the duty cycle of A is 30%, the duty cycle of B is 70%.
    etc

    Is that right? If so, do you need dead time between the positive pulses on the two outputs?

  23. Christos says:

    Hello Mr. Ted,
    First of all I want to express how much I appreciate your help!
    I would like to ask you why you filter the voltage from pin 23 and not from both (18 and 23) and why do you send it to AN1? Is AN1 acting as the input of the PI controller?
    By the term “setpoint” do you mean the output signal of the irradiance sensor?
    Finally, why is the dead time actually needed? When I designed this project in Simulink or when I did the maths to calculate everything I have not considered such a parameter. Is it a parameter that has to do entirely with the programming part?

    • batchloaf says:

      The only reason I’m filtering the signal from pin 23 (OC1) is to simulate the effect of driving some kind of load with the PWM signal. It’s basically a “dummy” plant that I’m going to control using the PI controller. The input to the dummy plant is the PWM signal and the output is the capacitor voltage. The setpoint (a voltage I’m setting with a simple potentiometer) is the “target” voltage for the output of the dummy system. The role of the PI controller is to increase or decrease the duty cycle of the PWM signal until the capacitor voltage (the output of the dummy system) matches the potentiometer voltage (the setpoint). Basically, when the duty cycle increases, the capacitor voltage slowly rises; but when the duty cycle decreases, the capacitor voltage slowly falls.

      Currently, I’m not using the output from pin 18 (OC2) because my dummy plant only has one input. However, because you need complementary PWM outputs, I assumed that you need to drive transistors in some kind of push-pull arrangement. Is that correct? If so, you normally need to leave a short dead time between switching one off and the other on. This prevents “shoot through” which occcurs in push-pull transistor circuits when both transistors accidentally get switched on simultaneously (even for a split second). The required dead time depends on the type of transistor you’re using (e.g. BJT, IGBT, MOSFET, etc) since different types switch on and off faster or slower. My colleague Kevin Gaughan suggested 2us dead time as a reasonable starting point when using IGBTs, so I included that in my program. If you’re not controlling this type of load, or don’t want dead time for some other reason, it should be easy to eliminate it from the program. You can probably just set it to zero.

      The term “setpoint” is used in control theory to describe the target state of a system that the controller is trying to achieve. For example, when you adjust the dial on a central heating thermostat, you are varying the “setpoint” – the target temperature for the central heating system. It should heat or cool the house in order to bring the actual temperature as close as possible to the target value.

      I’m now a bit confused about what the setpoint is in your system. A PI controller needs a reference input to tell it what value it’s aiming to get the system output to. Perhaps I don’t properly understand the system you’re controlling. Can you show me the simulink model you’re using please?

      Also, please take a look at the following Wikipedia article on PID control. It should hopefully clarify some of the terminology. In that article, the setpoint is determined by r(t), the reference input. The PID controller tries to bring y(t), the plant output, as close as it can to r(t), the reference input. (Incidentally, a PI controller is just the same as a PID controller with the derivative term set to zero – i.e. Kd = 0)

      http://en.wikipedia.org/wiki/PID_controller

      Ted

      • Christos Kokkides says:

        Hello Ted, thanks again for your help. Via this e-mail I have attaches my simulink file. The final project can be found by opening the “PVandConverterAndInverterCLS” file. I see what you mean with the reference point of the PI controller. As you can see from my simulink file attached, the reference point of my PI is by a s-function that I have done. This s-function receives the irradiance value (irradiance sensor for the hardware case) and decides via a data base that I have done what the reference value must be. The aforementioned database consists of two arrays that include 20 different irradiance values with the corresponding voltage value. I did this by simulating a PV in MATLAB for a couple of times calculating the MPPT.

        On Wed, Jun 12, 2013 at 3:17 PM, “ad hocumentation n. fast, instinctive documentati

      • Christos says:

        Hello Ted,
        thanks again for your help. I have sent you an e-mail as a reply to yours and have attached my simulink file. The final project can be found by opening the “PVandConverterAndInverterCLS” file.
        I see what you mean with the reference point of the PI controller. As you can see from my simulink file attached, the reference point of my PI is by a s-function that I have done. This s-function receives the irradiance value (irradiance sensor for the hardware case) and decides via a data base that I have done what the reference value must be.
        The aforementioned database consists of two arrays that include 20 different irradiance values with the corresponding voltage value. I did this by simulating a PV in MATLAB for a couple of times calculating the MPPT.
        If you have not received my e-mail or the attachment please tell me how you I can send you my simulink file.

        Thanks Again

      • batchloaf says:

        Hi Christos,

        I’m afraid I didn’t receive any email. Can you just put the file(s) into your dropbox or google drive, then share the file publicly and post the link here? That’s the easiest way to do it. It should only take a minute to publish it on google drive since you already have a gmail account.

        Ted

  24. Christos says:

    Hello Ted,
    this is the dropbox link with my simulink files:
    https://www.dropbox.com/sh/sptakcpviuyyk3o/Fuxugxjtup

  25. Christos says:

    Hello Mr Ted,
    I would like to ask you if you have seen my simulink file and if you have understood what I am actually trying to program on the dsPIC?
    Thank You

    • batchloaf says:

      Hi Christos,

      I was able to access the zip file in your dropbox, but I haven’t had a chance to look at it closely yet because I’m flat out writing papers for a conference deadline. Also, I don’t have MATLAB here at home, so I won’t be able to open the simulink model until I’m back in the office on Monday. In the meantime, if you get a second, maybe you could take a screenshot of the simulink model and throw that into dropbox too? That way, I might get a chance to take a quick look before Monday.

      Ted

      • Christos says:

        Hello Mr Ted,
        I have just added a screenshot to my dropbox link. Is it ok with you if I delete now my simulink file from dropbox for safety reasons, since it is my main project?

      • batchloaf says:

        Thanks Christos. I’ve downloaded both files now, so if you’re worried about leaving them in dropbox, you can delete them now!

        Ted

  26. Christos says:

    Hello Mr Ted,
    I would like to ask you if you have any news with the simulink files I have sent you the other time. I know you have a lot of work to do and I do understand.

    Thanks in Front
    Christos

  27. abdel says:

    hello
    I’m New in programming dsPIC
    I’d like to know how to solve my problem
    I sinusoideaux two signals X1, X2 of phase 90 deguré that are connected to the two input AN0, AN1.
    I want to do the following opèreation arctangante (X1/X2). obtain and as a result tringulaire signal on the PWM output
    thank you in advance

    • batchloaf says:

      Hi Abdel,

      So, are X1 and X2 both sinusoidal, but 90 degrees out of phase with each other?

      If so, when you say get the arctan of (X1/X2), do you mean the magnitude of one sinusoid divided by the magnitude of the other sinusoid?

      If so, I can probably create a very simple example program which will show you how to start at least. However, it would be useful to know some more details, such as the voltage range of the two input signals, etc.

      Ted

  28. Christos says:

    Hello Mr Ted,
    I would like to ask you if you have my simulink files I have sent you the other time. I have not been able to use the code you have prepared for me.

    Thanks in Front
    Christos

  29. Giorge says:

    Dear Mr Ted

    I have heard of your forum and how helpful you are with students having difficulties in programming and I would like to ask for your help.
    I am currently trying to build and test a DC/AC inverter with 5 switches (H5, https://docs.google.com/viewer?url=patentimages.storage.googleapis.com/pdfs/US20050286281.pdf). The 5 switches of the inverter switch with different PWM patterns. Two switches of the full bridge (S1-S3) are driven by a PWM signal at the grid frequency (50Hz) and 50% duty cycle but are complimentary. The other two switches (S2-S4) switch at higher frequency with a sinusoidal PWM pattern (at 20kHz) following the on/off pattern of S1/S3. Finally for the 5th switch the PWM pulse is sinusoidal (as S2/S4) but it conducts continuously. The sin signal used to produce the sinPWM pulse must be at 50Hz to produce an AC output of 50Hz.
    I have simulated the inverter using Simulink and I can send you the file if you need it.

    Thank you in advance
    Giorge

  30. Song says:

    Hi Ted,

    Haven’t talked to you in a while. How are you?
    Now,my work almost done. Because of your help, so I want to say “Thank you so much”.

    It’s my lucky that I found you. 🙂
    Regards,
    Song

  31. vigneshkkumar says:

    hello,
    if i m measuring a analog signal and storing it in a variable for example Vmeasure, how could i read the value stored in that variable.i.e i want to know the decimal or hexadecimal number equivalent of measured analog signal. i m using c30 compiler.

  32. batchloaf says:

    Hi Vignesh,

    You mean you want to be able to see the number yourself – is that right? If so, there are a couple of ways to do it:

    1. The first way is to use MPLAB to debug your program. In this approach, you would insert a breakpoint into the program just after the analog input is read into the variable. Then you can either just hover the mouse pointer over the variable and its current value will be displayed, or you can add the variable to the watch window so that its value is displayed all the time. Personally, I don’t use MPLAB so I don’t use the debugger, but this is how a lot of people keep an eye on the value of variables.
    2. Another way of doing it, which I use all the time myself, is to set up the UART so that you can transmit text from the PIC to the PC and then use printf to display the value of the variable on the PC screen, I’ll include a short code example below.
    //
    // dsPIC30F4011 example - print analog readings
    // Written by Ted Burke
    // Last updated 10-1-2014
    //
     
    #include <xc.h>
    #include <stdio.h>
    #include <libpic30.h>
     
    // Configuration settings
    _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
    _FWDT(WDT_OFF);                  // Watchdog timer off
    _FBORPOR(MCLR_DIS);              // Disable reset pin
     
    // Function prototype
    unsigned int read_analog_channel(int n);
     
    int main()
    {
        int voltage;
    
        // Make RD0 a digital output
        _TRISD0 = 0;
        
        // Configure AN0-AN8 as analog inputs
        ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
        ADCON1bits.ADON = 1;   // Turn ADC ON
     
        // Setup UART
        U1BRG = 48;            // 38400 baud @ 30 MIPS
        U1MODEbits.UARTEN = 1; // Enable UART
        
        while(1)
        {
            _LATD0 = 1; // LED on
            
            // Read a voltage from AN0 and print it via serial port
            voltage = read_analog_channel(0);
            printf("Voltage = %d\n", voltage);
            
            _LATD0 = 0; // LED off
            
            __delay32(30000000); // 1 second delay
        }
     
        return 0;
    }
      
    // This function reads a single sample from the specified
    // analog input. It should take less than 5us when the
    // microcontroller is running at 30 MIPS.
    // The dsPIC30F4011 has a 10-bit ADC, so the value
    // returned is between 0 and 1023 inclusive.
    unsigned int read_analog_channel(int channel)
    {
        ADCHS = channel;          // Select the requested channel
        ADCON1bits.SAMP = 1;      // Start sampling
        __delay32(30);            // 1us delay @ 30 MIPS
        ADCON1bits.SAMP = 0;      // Start Converting
        while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
        return ADCBUF0;
    }
    

    Also, this is the build script I used for the above example (using the XC16 compiler):

    xc16-gcc main.c -mcpu=30F4011 -Wl,--script=p30F4011.gld
    if errorlevel 0 xc16-bin2hex a.out
    

    To display the readings on the PC screen, the easiest thing to do is leave the PICkit 2 connected to the PIC circuit and then use the UART tool in the PICkit 2 software application (look for “UART tool…” under the Tools menu). For the example code above, you’ll need to set the UART tool to 38400 baud (i.e. the same baudrate as the PIC). Here’s a screenshot of how the above example looked in the UART tool when I tried it out:

    In the above screenshot, you can see me varying the voltage on pin AN0. I have a potentiometer connected to the pin so that I can vary the input voltage between Vss (0V) and Vdd (5V). In the screen shot, I turned the pot all the way up, then all the way down, then left it at about 1/3 of the way up from 0.

    You can also use a serial adapter to transmit the readings to the PC and display them in any software that can open a serial port and display the incoming data on the screen.

    Regards,
    Ted

    • vigneshkumar says:

      thanks Mr.Ted. following is the coding i ve used for generating pwm signals of 20kHz,

      #include
      #include
      #include
      //#define FOSC 40000000LL //clock frequency in Hz
      //#define FCY (FOSC/4) //MCU is running at FCY MIPS

      // OSCLILLATOR CONFIGURATION

      _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16×7.5MHz, Fcy=30MHz
      _FWDT(WDT_OFF); // Watchdog timer off
      _FBORPOR(MCLR_DIS); // Disable reset pin

      int main(void)
      {
      // PWM period = Tcy * prescale * PTPER = 33ns * 1 * PTPER
      // PWM pulse width = (Tcy/2) * prescale * PDCx

      PTPER = 1500; // frequency of PWM pulse is 20kHz

      PTCON = 0x8000; // Enabling the PWM module;
      PWMCON1 = 0x0101; // RE0, is configured as PWM output.
      PWMCON2 = 0x0000; // Configured to obtain Duty Cycle through PDC registers
      PTMR = 0x0000;

      PDC1 = 750;
      while(1); // infinite Loop

      }

      my problem is while i configure the pwm in freerunning mode, if my PTPER value is 1500 and for PDC1= 750 i am not able to get 50% duty ratio, instead i m getting 25%. how should i configure PWM in free running/edge aligned mode to get 50 % duty ratio for the above said PTPER and PDC1 values..could you please help in fixing it.

      • batchloaf says:

        Hi Vignesh,

        What you’re seeing is absolutely normal. PTPER and PDC1 effectively use different units of time. In free running edge-aligned PWM mode, the following formula gives you the PWM period:

        Tpwm = (PTPER + 1) * PrescaleValue * Tcy
        

        However, the pulse width is given by

        Tpw = PDC1 * PrescaleValue * (Tcy / 2)
        

        In other words, (assuming a prescaler value of 1:1 for simplicity) PTPER specifies the period in units of Tcy, whereas PDC1 specifies the pulse width in units of Tcy/2.

        Personally, I find this unit inconsistency very confusing, and most of my students agree, so I’ve actually switched from teaching PWM with the PWM module to teaching it with the Output Compare module which also does a great job generating PWM signals, but all times are specified as multiples of Tcy which makes things simpler.

        Anyway, the good news is that the solution to your problem couldn’t be simpler. If you want a 50% duty cycle, just put the exact same value into PTPER and PDC1.

        If you want to find out more about this, I recommend looking at the PWM chapter in the dsPIC30F Family Reference Manual (especially section 15.4), but be warned: it’s not exactly a page-turner!

        Ted

  33. vigneshkumar says:

    thanks Mr.Ted. i have tried to debug my program using pickit3 debugger tool. it is successfully programmed but then when i clicked run it is showing following message
    Running..
    Target halted.
    so i reconnected the pickit3 but it is showing this message now..

    PICkit 3 detected
    Connecting to PICkit 3…
    Running self test…
    Self test completed
    Firmware Suite Version…… 01.29.33
    Firmware type………………….dsPIC30F
    PICkit 3 Connected.
    Target Device ID (00000000) does not match expected Device
    ID (01010000).

    what is problem?…please help me as i m new to mplab …

    • batchloaf says:

      Hi Vignesh,

      I’m afraid I don’t use MPLAB and I don’t have a PICkit 3, so I may not be much help here. However, it sounds like your dsPIC may not be correctly connected to the PICkit 3. Could you possibly share a high resolution photo of your circuit with the PICkit 3 connected? If so, I’ll take a look and see if I can spot a problem.

      You won’t be able to upload a photo directly in your comment here, but if you upload the photo to Google drive (which you should have access to since you have gmail) and then share it publicly, you can just include a link to the image here in your comment.

      Thanks,
      Ted

  34. vigneshkumar says:

    hi Mr.Ted
    could you please tell me how to write a data into eeprom of dispic30f4011 that is stored in a variable. for eg.
    Vmeasure=read_analog_channel(2);
    error=Vref-Vmeasure;

    i need to write the value in variable error to specified location in eeprom. i m using c30 compiler

    • batchloaf says:

      With the C30 compiler, I’m not sure, but with the XC16 compiler, you can declare an array in EEPROM something like the following:

      __eds__ int my_data[10] __attribute__((space(eedata)));
      

      You can then use the elements in this array to store data into EEPROM and read it back out. To store your value into EEPROM:

      Vmeasure=read_analog_channel(2);
      error=Vref-Vmeasure;
      my_data[0] = error;
      

      Then, to read the value back out of EEPROM:

      error = my_data[0];
      

      I haven’t actually used this myself, so there might be more to this than I realise, but this is how it looks in Section 10.10 of the XC16 compiler User’s Guide:

      Click to access 50002071C.pdf

      Hope that helps.
      Ted

  35. sanju says:

    NICE SIR….GOD BLESS U TO HELP US BY TEACHING IN PROPER WAY…IAM STARTING DSPIC NOW…

  36. John says:

    Hi Mr Ted. I’m new to this and I want to program the the 4011 to be able to read a value thats converted by the ADC to produce a PWM. I want to make it so that the 4011 can read a flex sensor and control a servo. Can you please help me?

    • batchloaf says:

      Hi John,

      I’ve just posted an example of servo angle control using an analog input voltage on the dsPIC30F4011. See here:

      http://roboted.wordpress.com/2014/02/27/servo-angle-controlled-by-an-analog-voltage-using-dspic30f4011/

      I’m working at home this morning, so I haven’t been able to check this program on a dsPIC. Therefore, if you have any problems getting it to work, please let me know.

      Regards,
      Ted

      • John says:

        Thanks for the reply. I was able to compile the code but I couldn’t try it yet because I haven’t assemble the voltage divider for the ADC. I would like to know how much can the ADC support. Would 5V be too much. I’m afraid of burning my components because I may need them. And I could only understand part of the code, so I do not know what is the supposed outcome. Will the code be able to turn my HD-1440 servo which can only turn about 180 degrees. Sorry asking so much from you. I’m pretty bad at these.

      • batchloaf says:

        Hi John,

        Assuming your dsPIC30F4011 is powered with 5V, then the ADC converts analog input voltages between 0V and 5V into digital values between 0 and 1023 (as long as the ADC is configured as in my example). So to answer your question, yes 5V input is fine.

        The code I posted generates pulse widths between 1ms and 2ms. According to the datasheet for the HD-1440, it accepts pulses between 0.8ms and 2.2ms, so you may not get quite the full 180 degree range of motion with this version of the code. However, it’s probably safer to begin testing with pulses that are definitely within the allowed range in case you wear out the servo by driving it beyond its mechanical limit. You can adjust the code later to tweak the range of motion – it just involves changing a couple of values (specifically the variables min, max, and range).

        Since the range of pulse widths generated by this code is comfortably within the allowed range (including a small safety margin), it should be perfectly safe to input 0V or 5V into AN0 (pin 2) to see the servo move back and forth. You can try taking a piece of wire and connecting AN0 (pin 2) to 0V and 5V alternately. If you have a potentiometer, that would be even better because you could connect the two ends of the potentiometer track to 0V and 5V and connect the wiper voltage to AN0, allowing you to move the servo to any position by adjusting the potentiometer.

        It should go without saying that you should proceed with caution at the start since I may have overlooked something. If you hear the servo grinding in what sounds like a bad way, turn off the power and double check everything!

        Ted

      • batchloaf says:

        PS FYI, the HD-1440 datasheet seems to indicate that the range of motion for pulses between 1ms and 2ms is about 90 degrees, so that’s what you should probably see if you alternate between 0V and 5V input on pin 2.

        Ted

      • John says:

        Thanks. I was understand more from you than any websites or forums that I could find.

      • batchloaf says:

        You’re welcome. Glad I could help!

        Ted

  37. vigneshkumar says:

    hi ted,

    how to generate a random number between 0 to 1 using rand() function. i dont know the maximum limit of random number generated from rand function. i m using c30 compiler. could you pls help me.

    • batchloaf says:

      Hi Vignesh,

      The maximum number returned by the rand() function may be different in each compiler – it’s not defined as any particular value in the C language. I’m not sure what the exact value is in C30, but each compiler provides its maximum value in a constant called RAND_MAX.

      So, I think what you want is something like:

      float x = ((float)rand()/(float)(RAND_MAX));
      

      That should give x a random value between 0 and 1. Give it a try and see if it works.

      Of course, you’ll probably get the exact same sequence of “random” values each time you power up the microcontroller unless you seed the random number generation with a genuinely random value. One way you might do that is recording noise from an analog input and combining a few readings to give you a nicely random seed number. For example (assuming you have a function called read_analog_channel(n) which returns a 10-bit unsigned int):

      #include <stdlib.h>
      
      ETC ETC...
      
      // Seed the random number generator
      a = read_analog_channel(0);
      b = read_analog_channel(0);
      srand((a << 10) + b);
      
      // Now, generate random numbers. For example...
      float x = ((float)rand()/(float)(RAND_MAX));
      

      Ted

  38. sunil says:

    sir,
    i ve problem when i connect pickit 2 and dspic30f 2010
    it can programe for two to three times then it seems an error message “cant read programme memmory starting adress like 0000×000, can you help me for this problem

    • batchloaf says:

      Hi Sunil,

      Were you able to program it previously and now it has stopped working, or have you not been able to program it yet at all?

      Also, is there a way you can share a high resolution photograph of your circuit so that I can check the connections?

      Ted

  39. John says:

    Hi Ted,

    I tried the code you posted at http://roboted.wordpress.com/2014/02/27/servo-angle-controlled-by-an-analog-voltage-using-dspic30f4011/

    I tried to display it to a LCD but I cant seem to get the conversion right. I tried to connect a voltage divider circuit with R2 being a flexible bend sensor. But no matter how much I bend the sensor, it seems that I can’t change my ADC value. Could you help me?

    • batchloaf says:

      Hi John,

      Have you checked the output of your voltage divider with a multimeter?

      Also, have you tried just feeding in 0V and 5V (or whatever Vdd you use in your circuit) into the analog input to see if it responds to that?

      Ted

      • John says:

        Hi Ted,

        Based on a multimeter, the output is about 2.5V (flex sensor straight) and 3.6V (about 180 degree bend).

        I tried directly connecting to the ADC channel to 5V and 0V. It works except the displaying the maximum value to LCD part. The displayed value is not accurate due to the conversion which I am also facing.

        However no matter how I tried to bend the flex sensor, the ADC doesn’t seem to change at all.
        I tested this by using BCD and there’s no change to the LCD display. The ADC reading will keep fluctuating from 0003 to 0004 normally and when I bend the sensor, at most it will increase the value by 1.

        When I tried on the HD-1440A servo, the servo will not turn. I tried on 0V and 5V. None will turn the motor unless I pull out the wire connecting the servo to GND. Doing so will turn the servo slightly and it doesn’t matter if I connect the ADC channel to 0V or 5V..

      • John says:

        Hi Ted,

        Sorry for spamming but I made a mistake. The code you posted was able to turn the servo. However, the servo kept spinning around at the same speed regardless of the ADC reading. I tried connecting the ADC channel (port 2) to GND and 5V but there’s no change.

      • batchloaf says:

        If the servo is physically able to revolve continuously, maybe it’s a continuous rotation servo in which pulse width controls speed of rotation rather than angle? Most angle servos are physically restricted to a certain range (e.g. 180 degrees), so it’s not possible for them to keep turning at a constant rate.

        Ted

      • John says:

        Yes that’s what I thought but based on the data sheet, the maximum travel is supposed to be approximately 165 degree.
        The datasheet states that it should only travel 90 degrees if the PWM is 1ms to 2ms.
        I read that this servo is often used for remote controlled aircraft.

      • batchloaf says:

        Hi John,

        If your servo is supposed to have a maximum travel of 165 degrees, but yours is rotating continuously (revolving around and around in the same direction), I suspect it may be faulty. Normally, a servo of that type is mechanically prevented from rotating beyond its limits, i.e. there are physical stops inside the servo mechanism. If those stops have become broken, it cannot be assumed that the angle sensing is working as normal, which would explain the continuous rotation.

        The actual driving element within the typical low-cost servo is just an ordinary DC motor. If the angle feedback mechanism is not functional and the mechanical limiters are not in place, the motor could turn contiuously.

        Is it possible to get your hands on another servo and try that to see if it works?

        Ted

  40. Hello everyone..I use the dsPIC30F4011 with MPLABX and PICKit3.When I run the microprocessor with FRC-PLL4 or PLL8,everything is fine. When I run it with FRC-PLL16, the processor burns out!Can anyone help me?I use these:
    _FOSC(CSW_FSCM_OFF & FRC_PLL16);
    _FWDT(WDT_OFF); // Watchdog timer off
    _FBORPOR(MCLR_EN)

    Are there any other configuration bits that I must set or maybe some settings in MPLABX?

    • batchloaf says:

      Hi Hara,

      So when you run the dsPIC30F4011 with FRC_PLL16 it literally burns out?! As in the chip is destroyed and cannot be used again?? Wow, that’s really really strange!!

      As microcontrollers go, the dsPIC is one of the sturdiest I’ve used and I very rarely see a whole chip burned out, despite having many students using them. Someone will fry a pin once in a while of course, but the rest of the chip usually lives to fight another day.

      Is it possible that something else in your circuit is somehow cooking the dsPIC as a consequence of the whole system running at a higher frequency? The sort of thing I’m thinking of is some kind of boost circuit or switching voltage converter which might generate a higher voltage when the circuit is driven “the same but faster”.

      I suggest trying your FRC_16DLL code on a chip with nothing else in the circuit and see if it runs ok.

      Also, perhaps you can you explain a bit more about the rest of the circuit and what your code is doing?

      Ted

      • Hi Ted,
        Thank you for your response. Actually I test the dsPIC in a breadboard. I wrote something very simple. I send pulses to an input and an interrupt is produced in the rising and falling edges via change notification. Nevermind, I test the PIC not only to do this code, but do only one addition and still don’t working. Do you think that it has to something with the breadboard? Or do I need to write something else in the code? If I debug it with PLL16, I cannot use it anymore,it is destroyed.Here is the code:

        #include “p30f4011.h”
        _FOSC(CSW_FSCM_OFF & FRC_PLL16); //if I write FRC_PLL4,everything is fine
        _FWDT(WDT_OFF);
        _FBORPOR(MCLR_EN & PWRT_OFF);
        _FGS(CODE_PROT_OFF);

        unsigned int a=0,b=0;

        int main()
        {
        a=a+1;
        b=a+1;
        }

      • batchloaf says:

        Hi Hara,

        This is a bizarre and interesting problem!

        When you say the chip is “destroyed”, can you please explain exactly how you’re reaching that conclusion? Does programming simply fail everytime you try after using FRC_16DLL? If so, please post the exact message you’re seeing.

        Also, have you tried programming one of the dead chips using the Integrated Programmer Environment (IPE) which is a standalone program installed alongside MPLABX?

        Finally, if you can share a high resolution photo of your breadboard circuit, I’ll see if I can spot any problems. However, it would be strange for a breadboard problem to cause this only in the FRC_DLL16 case.

        Ted

  41. When I run the code with PLL16, the debugger says that it was expected value: 40100 and received 0.I have checked all the supplies and all the connections,nothing wrong. When I get that message in mplabx, then no matter what code I write (even with PLL4),the PIC doesn’t respond.So I think it is destroyed. I tested the code in another PIC that was in a PCB and it works!!So I guess that something in this breadboard goes wrong.

  42. lopes says:

    Hi Ted,
    I need your help.
    I’m getting a speed problem with with the 30F4011. It’s seem that my dspic is running very slow.
    No metter what I configure, the simple complement of pin D4 I can’t get the output more than a 700kHz pwm. I thing it should be in the Mhz values.
    I’m using mplab 8, C30 compiler with a simple code like:

    #include
    _FOSC(FRC_PLL16); //7,3728 MHZ x 16 = 117,9648 MHZ
    void SetupPorts(void);
    int main (void)
    {
    SetupPorts();
    while(1) {
    _LATD3=~_LATD3;
    }
    }

    Am I doing something wrong? Thanks.

    • batchloaf says:

      Hi Lopes,

      With FRC_PLL16, your chip should be running at a clock frequency of 120MHz. However, like most PICs, the dsPIC30F4011 only performs one instruction every four clock cycles. Therefore, the instruction frequency is 30 MIPS (million instructions per second). Furthermore, each line of C code can easily translate into quite a few processor instructions. Each iteration of your “while(1)” loop will almost certainly compile into a large number of machine instructions. You can check this in MPLAB by looking at the disassembled code.

      Different compilers (or versions of the XC16 compiler) may produce more or less optimised code, and may therefore produce different frequencies on the output pin.

      To get the pin toggling really fast (every 3 or 4 instruction cycles), you may need to hand craft the loop with inline assembly code. This wouldn’t be too difficult to do – you should be able to find an example online somewhere.

      If that still doesn’t explain the low rate of iteration you’re seeing, you could try replacing this line:

      _FOSC(FRC_PLL16); //7,3728 MHZ x 16 = 117,9648 MHZ
      

      with these lines…

      _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
      _FWDT(WDT_OFF);                  // Watchdog timer off
      _FBORPOR(MCLR_DIS);              // Disable reset pin
      

      …in case the watchdog timer is resetting the chip or something?

      Ted

  43. Pingback: LED Flashing using DSPIC30F4011 | Indoor Positioning System

  44. Vignesh Sundaram says:

    Hi Ted ,

    I tried running the build.bat file from cmd . I got the following error.

    ‘xc16-gcc’ is not recognized as an internal or external command , operable program or batch file.
    ‘xc16-bin2hex’ is not recognized as an internal or external command , operable program or batch file.

    I made sure that the build.bat was in the same folder as my C source code.

    can you throw some light on this .

    Thanks ,
    Vignesh

    • batchloaf says:

      Hi Vignesh,

      Have you installed the XC16 compiler, as described in the section “What software to install” ? If XC16 is not installed, or is not installed correctly, the programs “xc16-gcc” and “xc16-bin2hex” will not be available because they are contained in that suite of programs.

      Another possible explanation is that the XC16 software is installed, but the installation folder has not been added to the path. You can check if the software is actually on your hard drive by searching for the installation folder. I used the default location on my machine which is:

      C:\Program Files\Microchip\xc16\v1.20\bin
      

      If that folder is there and it contains the programs “xc16-gcc” and “xc16-bin2hex”, but they are still not being found when you run build.bat, then you probably need to add the folder “C:\Program Files\Microchip\xc16\v1.20\bin” to the path. Do you know how to do that?

      Ted

  45. Vignesh Sundaram says:

    Ted,

    The scripts working . xC16 was installed, but i had to add the path , in my Environment Variables setting . Thanks a lot .

    Your blog is a great resource for dsPIC enthusiasts. I will post any interesting challenges i come across in my work . I am working on Active Power Factor Correction Techniques in DC-DC Converters.

    Vignesh

    • batchloaf says:

      Hi Vignesh,

      That’s great that you got it working! Thanks for letting me know.

      I’m interested in the area of active power factor correction, especially using the dsPIC since that’s something I enjoy working with so much, so do please let me know if you come up with anything interesting.

      Ted

  46. Payrav says:

    Hi Ted. My name is Payrav. I am from Russia. I am doing a project to control LED blinking using dspic30f4011. I must controlling LED blinking with potentiometer. The potentiometer connected in input on pin 6 . The LED is on pin10 (RB8).
    Please, help.
    Regards, Payrav.

    • batchloaf says:

      Hi Payrav,

      It sounds like you need something like this:

      //
      // dsPIC30F4011 example - LED blink controlled by pot
      // Written by Ted Burke, Last updated 31-10-2014
      //
      // This example blinks an LED on RB8 (pin 10) at a rate which depends
      // on the analog voltage measured on AN4 (pin 6).
      //
      // PLEASE NOTE: THIS CODE HAS NOT BEEN TESTED - THERE MAY BE ERRORS!
      //
       
      #include <xc.h>
      #include <libpic30.h>
       
      // Configuration settings
      _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
      _FWDT(WDT_OFF);                  // Watchdog timer off
      _FBORPOR(MCLR_DIS);              // Disable reset pin
       
      unsigned int read_analog_channel(int channel);
       
      int main(void)
      {
          // Declare a variable to store the measured analog voltage
          int voltage;
           
          // Configure RB8 as a digital output
          ADPGFG = 0x0100; // disable analog input on pin 10
          _TRISB8 = 0;     // use pin 10 as digital output
          
          // Configure analog inputs (pins AN0 - AN7)
          ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
          ADCON1bits.ADON = 1;   // Turn ADC ON
       
          // Blink LED on RB8
          while(1)
          {
              // Read analog voltage on pin 6 (AN4)
              // The value returned is between 0 and 1023
              voltage = read_analog_channel(4);
              
              // Blink LED on RB8 (duration depends on measured voltage)
              _LATB8 = 1;                  // LED on
              __delay32(voltage * 30000L); // delay depends on voltage
              _LATB8 = 0;                  // LED off
              __delay32(voltage * 30000L); // delay depends on voltage
          }
      }
      
      // This function reads a single sample from the specified
      // analog input. It should take less than 5us when the
      // microcontroller is running at 30 MIPS.
      // The dsPIC30F4011 has a 10-bit ADC, so the value
      // returned is between 0 and 1023 inclusive.
      unsigned int read_analog_channel(int channel)
      {
          ADCHS = channel;          // Select the requested channel
          ADCON1bits.SAMP = 1;      // Start sampling
          __delay32(30);            // 1us delay @ 30 MIPS
          ADCON1bits.SAMP = 0;      // Start Converting
          while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
          return ADCBUF0;
      }
      

      Regards,
      Ted

  47. Payrav says:

    Thank you so much for reply Ted.

  48. Payrav says:

    Hi Ted, your example around an LED blinking was very useful. I have another question. I am doing a project to control DC motor using a thyristor converter. The problem is on synchronization
    of the thyristors with a phase source voltages. How can I do this synchronization. And how to control phase stifts of the thyristors. The three phase thyristor converter consists 6 thyristors.
    Regards, Payrav.

  49. Payrav says:

    Mr Ted,
    Can you show us one simple example on how to control any tryristor converter?
    My tutor has said to me that I should use input capture module for synchronization of the thyristors with phase voltages of a source.
    Can you give us any simple example around it?
    Regards, Payrav.

    • batchloaf says:

      Hi Payrav,

      Sorry, I forgot to reply to your comment. Things are very busy here.

      What sort of example are you looking for? Just a simple example of using the input capture module on the dsPIC or something specific to controlling the six thyristors?

      I’m no expert on thyristors, but as I understand it they are turned on by a gate pulse and continue conducting as long as they are forward biased (or above a threshold current) – is that correct? Perhaps what you’re trying to do is use the dsPIC to deliver pulses to turn on each of the six thyristors at just the right time, where each one is synchronised to a particular point in an AC waveform?

      If you can tell me a bit more, maybe I can show you an example, but right now I’m not quite sure what it is you need to do.

      Ted

      • Payrav says:

        Hi Mr Ted, I am trying to control a DC motor using the thyristor converter (six thyristors). First of all I should to measure time period (frequency) of the Timer2 using Input capture module IC7.I capture only a rising edge. A time period should be 10ms. After the PWM will start in the independent mode. I have wrote something using your codes. I checked the results on an osciloscope but something is wrong. I can not to synchronize the PWM signals to the source signal. The code is like this: Please correct it. And please answer me where did I do a mistake.

        #include
        #include

        // Configuration settings
        _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16×7.5MHz, Fcy=30MHz
        _FWDT(WDT_OFF); // Watchdog timer off
        _FBORPOR(MCLR_DIS); // Disable reset pin

        // Function prototypes
        void configure_pins();
        void __attribute__((__interrupt__, __auto_psv__)) _IC7Interrupt(void);
        void __attribute__((__interrupt__, __auto_psv__)) _T2Interrupt(void);
        unsigned int read_analog_channel(int n);

        int main()
        {
        int voltage = 0;
        int timePeriod = 0;

        // Set up which pins are which
        configure_pins();

        while(1)
        {
        if (timePeriod = PR2) _LATB8 = 1;
        else _LATB8 = 0;

        // Analog input 0 controls PWM 2 duty cycle.
        voltage = read_analog_channel(0);
        PDC2 = (int)((voltage / 1023.0) *2* PTPER);
        }

        return 0;
        }

        void configure_pins()
        {
        // Configure RB0 as a digital output
        LATB = 0;
        TRISB = 0b011111111;
        TRISE = 0;
        // Configure analog inputs
        TRISB = 0x00FF; // Port B all inputs exept R8
        ADPCFG = 0xFF00; // Lowest 8 PORTB pins are analog inputs (RB0-RB7)
        ADCON1 = 0; // Manually clear SAMP to end sampling, start conversion
        ADCON2 = 0; // Voltage reference from AVDD and AVSS
        ADCON3 = 0x0005; // Manual Sample, ADCS=5 -> Tad = 3*Tcy = 0.1us
        ADCON1bits.ADON = 1; // Turn ADC ON

        // Configure Input Capture Module IC7
        IC7CONbits.ICM= 0b00; // Turn off input capture module IC7
        IC7CONbits.ICTMR= 1; // TMR2 contents are captured
        IC7CONbits.ICI= 0b01; // Interrupt on every capture event
        IC7CONbits.ICM= 0b011; // Capture mode every rising edge

        // Enabling Capture Interrupt for TMR2
        _IC7IP = 1; // The Level of priority IC7
        _IC7IF = 0; // Interrupt bit is cleared
        _IC7IE = 1; // Set the IC7 interrupt enable bit

        // Configure Timer 2.
        // PR2 and TCKPS are set to call interrupt every 10ms.
        // Period = PR2 * prescaler * Tcy = 1172 * 256 * 33.33ns = 10ms
        T2CON = 0; // Clear the Timer 2 configuration
        TMR2 = 0; // Reset Timer 2 counter
        PR2 = 1172; // Set the Timer 2 period (max 65535)
        T2CONbits.TCS = 0; // Select internal clock (Fosc/4)
        T2CONbits.TCKPS = 3; // Prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
        _T2IP = 1; // Set the Timer 2 interrupt priority
        _T2IF = 0; // Clear the Timer 2 interrupt flag
        _T2IE = 1; // Enable Timer 2 interrupt
        T2CONbits.TON = 1; // Turn on Timer 2

        // Capture interrupt service routine
        unsigned int timePeriod= 0;
        void __attribute__((__interrupt__, __auto_psv__)) _IC7Interrupt(void)
        {
        unsigned int previous_value, current_value;
        current_value = IC7BUF;
        previous_value = IC7BUF;
        if (current_value>previous_value)
        timePeriod = current_value-previous_value;
        else
        timePeriod = (PR2-previous_value)+current_value;
        T2CONbits.TON=0; // Stop Timer 2
        timePeriod=IC7BUF; // Save a captute value
        IC7CONbits.ICM=0b00; // Turn off IC7

        _IC7IF=0; // Clear the IC7 interrupt flag

        }

        // Configure PWM for free running mode
        // PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * 9470 = 20ms
        // PWM pulse width = (Tcy/2) * prescale * PDCx = 0.33/2 * 64* 9470=10ms;
        //

        PWMCON1bits.PMOD3 = 1; // PWM I/O pin pair is in the independent output mode
        PWMCON1bits.PMOD2 = 1; // PWM I/O pin pair is in the independent output mode
        PWMCON1bits.PMOD1 = 1; // PWM I/O pin pair is in the independent output mode

        PWMCON1bits.PEN3H = 1; // PWM3H pin is enabled for PWM output
        PWMCON1bits.PEN2H = 1; // PWM2H pin is enabled for PWM output
        PWMCON1bits.PEN1H = 1; // PWM1H pin is enabled for PWM output

        PWMCON1bits.PEN3L = 1; // PWM3L pin is enabled for PWM output
        PWMCON1bits.PEN2L = 1; // PWM3L pin is enabled for PWM output
        PWMCON1bits.PEN1L = 1; // PWM3L pin is enabled for PWM output

        OVDCONbits.POVD3H = 1; // PWM3H is controlled by the PWM generator
        OVDCONbits.POVD2H = 1; // PWM2H is controlled by the PWM generator
        OVDCONbits.POVD1H = 1; // PWM1H is controlled by the PWM generator

        OVDCONbits.POVD3L = 1; // PWM3H is controlled by the PWM generator
        OVDCONbits.POVD2L = 1; // PWM2H is controlled by the PWM generator
        OVDCONbits.POVD1L = 1; // PWM1H is controlled by the PWM generator

        OVDCONbits.POUT3H = 0; // PWM3H is driven INACTIVE
        OVDCONbits.POUT2H = 0; // PWM2H is driven INACTIVE
        OVDCONbits.POUT1H = 0; // PWM3H is driven INACTIVE

        OVDCONbits.POUT3L = 0; // PWM3L is driven INACTIVE
        OVDCONbits.POUT2L = 0; // PWM2L is driven INACTIVE
        OVDCONbits.POUT1L = 0; // PWM3L is driven INACTIVE

        PTCON = 0;
        _PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
        PTPER = 9470; // 20ms PWM period (15-bit period value)
        PDC1 = 0; // 0% duty cycle on channel 1 (max is 65536)
        PDC2 = 0; // 0% duty cycle on channel 2 (max is 65536)
        PDC3 = 0; // 0% duty cycle on channel 3 (max is 65536)
        PTMR = 0; // Clear 15-bit PWM timer counter
        _PTEN = 1; // Enable PWM time base
        }

        // Timer2 Interrupt Service Routine
        void __attribute__((__interrupt__, __auto_psv__)) _T2Interrupt(void)
        {
        _T2IF = 0; // Reset the flag of Timer2
        }

        // This function reads a single sample from the specified
        // analog input. It should take less than 2.5us if the chip
        // is running at about 30 MIPS.
        unsigned int read_analog_channel(int channel)
        {
        ADCHS = channel; // Select the requested channel
        ADCON1bits.SAMP = 1; // start sampling
        __delay32(30); // 1us delay @ 30 MIPS
        ADCON1bits.SAMP = 0; // start Converting
        while (!ADCON1bits.DONE); // Should take 12 * Tad = 1.2us
        return ADCBUF0;
        }

        Regars,
        Payrav

      • Payrav says:

        Hi Mr Ted, I am trying to control a DC motor using the thyristor converter (six thyristors). First of all I should to measure time period (frequency) of the Timer2 using Input capture module IC7.I capture only a rising edge. A time period should be 10ms. After the PWM will start in the independent mode. I have wrote something using your codes. I checked the results on an osciloscope but something is wrong. I can not to synchronize the PWM signals to the source signal. The code is like this: Please correct it. And please answer me where did I do a mistake.

        #include
        #include

        // Configuration settings
        _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16×7.5MHz, Fcy=30MHz
        _FWDT(WDT_OFF); // Watchdog timer off
        _FBORPOR(MCLR_DIS); // Disable reset pin

        // Function prototypes
        void configure_pins();
        void __attribute__((__interrupt__, __auto_psv__)) _IC7Interrupt(void);
        void __attribute__((__interrupt__, __auto_psv__)) _T2Interrupt(void);
        unsigned int read_analog_channel(int n);

        int main()
        {
        int voltage = 0;
        int timePeriod = 0;

        // Set up which pins are which
        configure_pins();

        while(1)
        {
        if (timePeriod = PR2) _LATB8 = 1;
        else _LATB8 = 0;

        // Analog input 0 controls PWM 2 duty cycle.
        voltage = read_analog_channel(0);
        PDC2 = (int)((voltage / 1023.0) *2* PTPER);
        }

        return 0;
        }

        void configure_pins()
        {
        // Configure RB0 as a digital output
        LATB = 0;
        TRISB = 0b011111111;
        TRISE = 0;
        // Configure analog inputs
        TRISB = 0x00FF; // Port B all inputs exept R8
        ADPCFG = 0xFF00; // Lowest 8 PORTB pins are analog inputs (RB0-RB7)
        ADCON1 = 0; // Manually clear SAMP to end sampling, start conversion
        ADCON2 = 0; // Voltage reference from AVDD and AVSS
        ADCON3 = 0x0005; // Manual Sample, ADCS=5 -> Tad = 3*Tcy = 0.1us
        ADCON1bits.ADON = 1; // Turn ADC ON

        // Configure Input Capture Module IC7
        IC7CONbits.ICM= 0b00; // Turn off input capture module IC7
        IC7CONbits.ICTMR= 1; // TMR2 contents are captured
        IC7CONbits.ICI= 0b01; // Interrupt on every capture event
        IC7CONbits.ICM= 0b011; // Capture mode every rising edge

        // Enabling Capture Interrupt for TMR2
        _IC7IP = 1; // The Level of priority IC7
        _IC7IF = 0; // Interrupt bit is cleared
        _IC7IE = 1; // Set the IC7 interrupt enable bit

        // Configure Timer 2.
        // PR2 and TCKPS are set to call interrupt every 10ms.
        // Period = PR2 * prescaler * Tcy = 1172 * 256 * 33.33ns = 10ms
        T2CON = 0; // Clear the Timer 2 configuration
        TMR2 = 0; // Reset Timer 2 counter
        PR2 = 1172; // Set the Timer 2 period (max 65535)
        T2CONbits.TCS = 0; // Select internal clock (Fosc/4)
        T2CONbits.TCKPS = 3; // Prescaler (0=1:1, 1=1:8, 2=1:64, 3=1:256)
        _T2IP = 1; // Set the Timer 2 interrupt priority
        _T2IF = 0; // Clear the Timer 2 interrupt flag
        _T2IE = 1; // Enable Timer 2 interrupt
        T2CONbits.TON = 1; // Turn on Timer 2

        // Capture interrupt service routine
        unsigned int timePeriod= 0;
        void __attribute__((__interrupt__, __auto_psv__)) _IC7Interrupt(void)
        {
        unsigned int previous_value, current_value;
        current_value = IC7BUF;
        previous_value = IC7BUF;
        if (current_value>previous_value)
        timePeriod = current_value-previous_value;
        else
        timePeriod = (PR2-previous_value)+current_value;
        T2CONbits.TON=0; // Stop Timer 2
        timePeriod=IC7BUF; // Save a captute value
        IC7CONbits.ICM=0b00; // Turn off IC7

        _IC7IF=0; // Clear the IC7 interrupt flag

        }

        // Configure PWM for free running mode
        // PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * 9470 = 20ms
        // PWM pulse width = (Tcy/2) * prescale * PDCx = 0.33/2 * 64* 9470=10ms;
        //

        PWMCON1bits.PMOD3 = 1; // PWM I/O pin pair is in the independent output mode
        PWMCON1bits.PMOD2 = 1; // PWM I/O pin pair is in the independent output mode
        PWMCON1bits.PMOD1 = 1; // PWM I/O pin pair is in the independent output mode

        PWMCON1bits.PEN3H = 1; // PWM3H pin is enabled for PWM output
        PWMCON1bits.PEN2H = 1; // PWM2H pin is enabled for PWM output
        PWMCON1bits.PEN1H = 1; // PWM1H pin is enabled for PWM output

        PWMCON1bits.PEN3L = 1; // PWM3L pin is enabled for PWM output
        PWMCON1bits.PEN2L = 1; // PWM3L pin is enabled for PWM output
        PWMCON1bits.PEN1L = 1; // PWM3L pin is enabled for PWM output

        OVDCONbits.POVD3H = 1; // PWM3H is controlled by the PWM generator
        OVDCONbits.POVD2H = 1; // PWM2H is controlled by the PWM generator
        OVDCONbits.POVD1H = 1; // PWM1H is controlled by the PWM generator

        OVDCONbits.POVD3L = 1; // PWM3H is controlled by the PWM generator
        OVDCONbits.POVD2L = 1; // PWM2H is controlled by the PWM generator
        OVDCONbits.POVD1L = 1; // PWM1H is controlled by the PWM generator

        OVDCONbits.POUT3H = 0; // PWM3H is driven INACTIVE
        OVDCONbits.POUT2H = 0; // PWM2H is driven INACTIVE
        OVDCONbits.POUT1H = 0; // PWM3H is driven INACTIVE

        OVDCONbits.POUT3L = 0; // PWM3L is driven INACTIVE
        OVDCONbits.POUT2L = 0; // PWM2L is driven INACTIVE
        OVDCONbits.POUT1L = 0; // PWM3L is driven INACTIVE

        PTCON = 0;
        _PTCKPS = 3; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
        PTPER = 9470; // 20ms PWM period (15-bit period value)
        PDC1 = 0; // 0% duty cycle on channel 1 (max is 65536)
        PDC2 = 0; // 0% duty cycle on channel 2 (max is 65536)
        PDC3 = 0; // 0% duty cycle on channel 3 (max is 65536)
        PTMR = 0; // Clear 15-bit PWM timer counter
        _PTEN = 1; // Enable PWM time base
        }

        // Timer2 Interrupt Service Routine
        void __attribute__((__interrupt__, __auto_psv__)) _T2Interrupt(void)
        {
        _T2IF = 0; // Reset the flag of Timer2
        }

        // This function reads a single sample from the specified
        // analog input. It should take less than 2.5us if the chip
        // is running at about 30 MIPS.
        unsigned int read_analog_channel(int channel)
        {
        ADCHS = channel; // Select the requested channel
        ADCON1bits.SAMP = 1; // start sampling
        __delay32(30); // 1us delay @ 30 MIPS
        ADCON1bits.SAMP = 0; // start Converting
        while (!ADCON1bits.DONE); // Should take 12 * Tad = 1.2us
        return ADCBUF0;
        }

        Regards,
        Payrav

  50. Brian says:

    Hi Mr. Ted,

    I need help in making a PFM signal for a dsPIC30F2020. I have code that gives me a properly working PWM signal for the dsPIC30F2020 with PID Control. However, when I change the code for the PWM to make the PFM, it doesn’t work. I’m using the dsPIC30F2020 trying to do a project that compares and contrasts PWM and PFM bucks converters. I have the PWM buck converter working perfectly. So for the PFM I used the exact same code and just switched from changing the duty cycle (PDC) with a constant period to changing the overall period (PTPER) with a constant duty cycle. However, the PID Control does not want to work or even a very simple “bang-bang” comparator like if statement – below. The full working PWM code is attached at the end of this post first and then it is followed by the NOT working PFM code.

    The code has a static setting having a constant off-time of 6.55us with about 257ns of dead time between the high and low PFM gate signals. I also set the maximum and minimum frequency at 130kHz and 50kHz, respectively. My ideal switching frequency is at 100kHz. In the static condition, I have confirmed the numbers output what I want on the oscilloscope. What it doesn’t do for me is actively adjust the period in order to regulate the output from the values it reads in from the ADC input pins AN0 (input voltage signal) and AN1 (reference voltage signal). Currently, it would just be “stuck” at the switching frequency of 140kHz and not respond by changing the period/frequency if the input voltage signal is higher or lower to the reference voltage signal going into the ADC input pins AN0 and AN1.

    I am using a high temperature part, so it is running at 20MIPS instead of the normal 30MIPS. Thus, the dsPIC clock period is 1.61ns instead of 1.05ns.

    I have read the data sheet to confirm that the PTPER can be changed at any time and not only when the PWM module is off – which is written at the beginning of Section 12.8 on page 125. (http://ww1.microchip.com/downloads/en/DeviceDoc/70000178d.pdf)

    Is there something I am overlooking with the setting of the PTPER register in my PFM.c code?

    Any help in this matter would be greatly appreciated.

    Thank you.

    =============================
    PWM CODE (WORKING)
    =============================

    #include “p30F2020.h”
    #include “dsp.h”
    #include “math.h”

    /* Configuration Bit Settings */
    _FOSCSEL(FRC_PLL)
    _FOSC(CSW_FSCM_OFF & FRC_HI_RANGE & OSC2_CLKO & HS_EC_DIS)
    _FWDT( FWDTEN_OFF & WINDIS_ON & WDTPRE_PR128 & WDTPOST_PS32768 )
    _FPOR(PWRT_128)
    _FGS( CODE_PROT_OFF & GWRP_OFF )
    _FBS(BSS_NO_FLASH)

    typedef signed int SFRAC16;

    #define Q15(X) ((X Q15(0.0) )
    {
    scaled_val = __builtin_mulsu(fooPID.controlOutput, MAX_DUTY_CYCLE) >> 15;
    }
    else
    {
    scaled_val = 0;
    }
    if( scaled_val < 64 )
    {
    scaled_val = 64; // see errata for min. duty cycle
    }

    PDC1 = scaled_val;
    PDC2 = scaled_val;
    }

    int main(void)
    {
    fooPID.abcCoefficients = &abcCoefficient[0]; //Set up pointer to derived coefficients */
    fooPID.controlHistory = &controlHistory[0]; //Set up pointer to controller history samples */
    PIDInit(&fooPID); //Clear the controler history and the controller output */

    kCoeffs[0] = Q15(0.4); // Kp + Ki + Kd must be < 0.99999
    kCoeffs[1] = Q15(0.2); // Kp + 2*Kd must be < 1.000
    kCoeffs[2] = Q15(0);
    PIDCoeffCalc(&kCoeffs[0], &fooPID); //Derive the a,b, & c coefficients from the Kp, Ki & Kd */

    init_PWM();

    while(1);
    }

    =============================
    PFM CODE (!!NOT WORKING!!)
    =============================

    #include "p30F2020.h"
    #include "dsp.h"
    #include "math.h"

    /* Configuration Bit Settings */
    _FOSCSEL(FRC_PLL)
    _FOSC(CSW_FSCM_OFF & FRC_HI_RANGE & OSC2_CLKO & HS_EC_DIS)
    _FWDT( FWDTEN_OFF & WINDIS_ON & WDTPRE_PR128 & WDTPOST_PS32768 )
    _FPOR(PWRT_128)
    _FGS( CODE_PROT_OFF & GWRP_OFF )
    _FBS(BSS_NO_FLASH)

    typedef signed int SFRAC16;

    #define Q15(X) ((X Q15(0.0) )
    {
    scaled_val = __builtin_mulsu(fooPID.controlOutput, MIN_FREQ) >> 15;
    }
    else
    {
    scaled_val = 0;
    }
    if( scaled_val < 4485 )
    {
    scaled_val = 4485; /* see errata for min. duty cycle of 64 and dead time. Max Fsw = 139.514kHz */
    }

    PTPER = scaled_val;
    }

    int main(void)
    {
    fooPID.abcCoefficients = &abcCoefficient[0]; //Set up pointer to derived coefficients */
    fooPID.controlHistory = &controlHistory[0]; //Set up pointer to controller history samples */
    PIDInit(&fooPID); //Clear the controler history and the controller output */

    kCoeffs[0] = Q15(0.4); // Kp + Ki + Kd must be < 0.99999
    kCoeffs[1] = Q15(0.2); // Kp + 2*Kd must be < 1.000
    kCoeffs[2] = Q15(0);
    PIDCoeffCalc(&kCoeffs[0], &fooPID); //Derive the a,b, & c coefficients from the Kp, Ki & Kd */

    init_PWM();

    while(1);
    }

  51. batchloaf says:

    Hi Brian,

    I’m a bit confused by the C code you included. Is it possible that WordPress has swallowed some important lines in the program? Both examples seem to jump suddenly into the middle of a function just after the “define Q15” line. Can you please check that it’s as you intended?

    In the meantime, I was also wondering about the following thing you mentioned…

    “So for the PFM I used the exact same code and just switched from changing the duty cycle (PDC) with a constant period to changing the overall period (PTPER) with a constant duty cycle.”

    When you say “constant duty cycle”, do you actually mean constant pulse width? I can’t see anything in the PFM example that varied PDC1, so I’m guessing this is the case, but I also can’t see where PDC1 gets initialised, so it’s possible that some of the missing code could vary PDC1 to maintain constant duty cycle (as a constant percentage of the period), rather than constant pulse width (i.e. fixed duration pulses).

    I’ll send you an email now in case you want to email back the full C files.

    Ted

  52. nesha says:

    Hi Mr. Ted,
    i want to generate pwm with adc
    please help me

    • batchloaf says:

      Hi Nesha,

      Do you mean that you want to control the duty cycle of a PWM signal based on an analog voltage which you’re reading via an ADC pin?

      If so, please specify the following:

      1. input voltage range (max and min analog voltage)
      2. PWM frequency
      3. PWM duty cycle range (max and min duty cycle as percentages)

      If you can provide that information, I’ll try to sketch out some example code.

      Ted

      • nesha says:

        yes i want,
        max analog voltage = 5
        min analog voltage =0
        PWM frequency 8KHZ
        PWM duty cycle : about 90-10
        and dead time is 6ms ;

        Thank you.

      • nesha says:

        yes i want to control the duty cycle of a PWM signal based on an analog voltage which reading via an ADC pins
        two Potentiometers are connected to AN0 & AN4 as analog inputs of adc. then i want to generate 3 pwm signal
        i want to control the duty cycle and range of pwm signal with these Potentiometers
        one Potentiometer control duty cycle and The other control range
        max analog voltage = 5
        min analog voltage =0
        switching frequency 8KHZ
        PWM duty cycle : about 90-10
        and dead time is 6ms ;

        pleas help me Mr.Ted
        Thank you.

      • batchloaf says:

        Hi Nesha,

        I just realised I never got back to you after you responded with additional details. Sorry about that – I was very busy last semester. Hopefully you got things working yourself in the meantime!

        Ted

  53. JJ says:

    Hi Mr Ted,

    I am working on a DC motor with dspic30F4011.. I need to control 2 DC motor with the use of PWM, encoders and since my motor is active high, therefore my PWM will be required to be a PWM1L and PWM2L.. any idea how can I start with this? my frequency required for now is 5kHz and my duty cycle is 25% and 75%.. voltage is 5v.. thank you..

  54. Chitra says:

    Hi Mr Ted,
    I am a M. tech student. I am doing project on Two Switch Buck Boost converter as an open loop I would like to generate a open loop for a pulse width of 45% anf 60% using dspic30F4011 as i am new to programming I would like to get a programming on this.
    Hope u will help me.
    Thank you

  55. vinay says:

    hello,
    kindly help me out with writing code for space vector PWM. im using dspic30f2010.
    im stuck in writing code for switching vectors

    thank you

  56. bill says:

    hello,
    I’m writing code for one project and i’m new to this. I’m using the dsPIC30F4011 and MPLAB. I measure one voltage from one capacitor and i compare this with one reference. This reference is one sinus, which has frequency 50Hz and i control its peak and its dc value through two trimmers respectively. The variance go through one PI controller, with limited output between 0.1 and 0.9, and compared with one ramp, which has frequency 20kHz. Also, this ramp has 0 and 1 for min and max value. So, i take one pulse and i drive two mosfets, with the original pulse and his additional. Can you give me one suggestion about the structure of the program and especially about the two trimmers.
    Thank you

  57. Pingback: ROBO 3.1 Software | aislinglee

  58. Rinson Antony says:

    Dear sir, could you please explain the method to set duty cycle registers for pwm ? How these duty cycle values are calculated ? And please explain one example.

    • batchloaf says:

      Hi Rinson,

      The PWM period depends on three things:

      1.) Tcy: the instruction cycle. When the chip is running at 30 MIPS (million instructions per second), Tcy = 33.33ns
      2.) _PTCKPS: the PWM prescaler setting. _PTCKPS is actually a pair of bits in the PTCON register.
      3.) PTPER: the PWM period register.

      The prescaler ratio depends on _PTCKPS as follows:

      – When _PTCKPS = 0, the prescaler ratio is 1:1
      – When _PTCKPS = 1, the prescaler ratio is 4:1
      – When _PTCKPS = 2, the prescaler ratio is 16:1
      – When _PTCKPS = 3, the prescaler ratio is 64:1

      So, the formula for the PWM period, Tpwm is:

          Tpwm = PTPER * prescaler_ratio * Tcy
      

      The PWM pulse width (and hence duty cycle) for each channel depends on three things. I’ll use channel 1 as an example here. The three things are:

      1.) Tcy: the instruction cycle
      2.) _PTCKPS: the prescaler setting
      3.) PDC1: the duty cycle register for PWM channel 1

      The formula for the pulse width is:

          pulse_width = (PDC1 * prescaler_ratio * Tcy) / 2
      

      Note that there is an extra factor of 2 there which gives a little extra resolution when you’re specifying the pulse width.

      Here’s an example…

      Supppose you want to set the PWM period to 20ms and the pulse width to 2ms.

      //
      // dsPIC30F4011 example - Simple PWM
      // Written by Ted Burke, Last updated 1-10-2015
      //
      
      #include <xc.h>
      #include <libpic30.h>
        
      // Configuration settings
      _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
      _FWDT(WDT_OFF);                  // Watchdog timer off
      _FBORPOR(MCLR_DIS);              // Disable reset pin
        
      int main(void)
      {
          // Configure PWM
          // PWM period = PTPER * prescale * Tcy = 9470 * 64 * 33.33ns = 20ms
          // PWM pulse width = PDC1 * prescale * Tcy / 2 = 1894 * 64 * 33.33ns / 2 = 2ms
          _PMOD1 = 0;   // PWM channel 1 mode: 0 for complementary, 1 for independent
          _PEN1H = 1;   // PWM1H pin enable: 1 to enable, 0 to disable
          _PTCKPS = 3;  // PWM prescaler setting: 0=1:1, 1=1:4, 2=1:16, 3=1:64
          PTPER = 9470; // Set PWM time base period to 20ms
          PDC1 = 1894;  // 2ms pulse width on channel 1
          _PTEN = 1;    // Enable PWM time base to start generating pulses
      
          // Now do nothing while pulses are generated by PWM module
          while(1) {}
      }
      

      Hope that helps!

      Ted

  59. aiman says:

    hi mr Ted, i’m trying to make a line following robot with pic30f4011 and motor driver L293d and ir sensors.

    as I’m a type of person that understands more or learn faster by looking at examples, i’m stuck at trying to program it, at least just to move without considering the line. the closer that i can make is for only a side of motor moving. 😅

    so I’m asking if you can explain or list to me what’s needed and maybe a snippet code for me to understand.

    i’ve done the main circuit, the sensor’s circuit, and learnt c programming for bout 8-9 month but just for general use, while for mplab only few days. i also done the robot’s mechanism, a 3 based.

    here is my circuit diagram : http://s16.postimg.org/mw6itmiyt/IMG_20151014_WA0017.jpg
    and motor im using : http://s15.postimg.org/aqorgbmjf/IMG_20151014_190956.jpg

    hope to hear from you soon 😀

  60. Chandrasekhar says:

    Hello sir.
    I need a programme for mppt controller.
    Using p and o algorithm,can you please help to write a programme, I have to snese current and voltage and based on it I have to calculate power, so based on change in power duty cycle should be controlled. Will you please help me to write programe for this please sir.

    • batchloaf says:

      Hi Chandrasekhar,

      You’re not giving me a lot to go on there, but you could try starting with something like this:

      //
      // MPPT example for dsPIC30F4011 using perturb and observe
      // Written by Ted Burke - last updated 23-1-2016
      //
      // Notes:
      //
      //  1.  Voltage sensing is on AN0 (pin 2)
      //  2.  Current sensing is on AN1 (pin 3)
      //  3.  PWM output is on PWM1H (pin 37)
      //  4.  PWM period is 1ms - I just gessed this.
      //  5.  P&O control loop period is 100ms approx - also a guess.
      //  6.  The duty cycle step size is currently 1% (i.e. 0.01) but that's just a guess.
      //  7.  The initial duty cycle is currently 25% - this should be set as desired.
      //  8.  The code won't compile until values are inserted for volts_per_du and amps_per_du.
      //  9.  This code is completely untested - I haven't even tried compiling it!
      //  10. I enabled the UART at 38400 baud so that debugging info can be printed.
      //
      
      #include <xc.h>
      #include <stdio.h>
      #include <libpic30.h>
      
      // Configuration settings
      _FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
      _FWDT(WDT_OFF);                  // Watchdog timer off
      _FBORPOR(MCLR_DIS);              // Disable reset pin
      
      void main()
      {
          // voltage, current, power, duty cycle
          const float volts_per_du=???, amps_per_du=???; // FILL IN VALUES HERE!!!
          int v_du, i_du;          // voltage and current in digital units
          float v, i;              // voltage in volts and current in amps
          float p_old, p_new;      // power in watt on previous and current cycles
          float duty_cycle = 0.25; // set this to desired initial duty cycle
      
          // duty cycle direction: 1 for increasing, -1 for decreasing
          int direction = 1;
          
          // duty cycle increases or decreases by this amount each cycle
          float step = 0.01;
      
          // Set up PWM output
          //
          //   PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * PTPER
          //   PWM pulse width = (Tcy/2) * prescale * PDC1
          //
          PWMCON1 = 0x00FF;      // Enable all PWM pairs in complementary mode
          PTCONbits.PTCKPS = 1;  // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
          PTPER = 7500;          // 1ms PWM period (15-bit period value)
          PDC1 = 0;              // controls duty cycle: PDC1=0 -> 0%, PDC1=15000 -> 100%
          PTCONbits.PTEN = 1;    // Enable PWM time base
      
          // Configure AN0-AN8 as analog inputs
          ADCON3bits.ADCS = 15;  // Tad = 266ns, conversion time is 12*Tad
          ADCON1bits.ADON = 1;   // Turn ADC ON
      
          // Setup UART
          U1BRG = 48;            // 38400 baud @ 30 MIPS
          U1MODEbits.UARTEN = 1; // Enable UART
          
          // Delay to let initial duty cycle take effect
          __delay32(3000000); // 100ms - just a guess!
          
          while(1)
          {
              // Read voltage and current from analog inputs
              // Both values are in digital units (du), meaning
              // that they are 10-bit unsigned integers (i.e.
              // whole numbers between 0 and 1023).
              v_du = read_analog_channel(0);
              i_du = read_analog_channel(1);
              
              // Convert the measured voltage and current to
              // untis of volts and amps.
              v = volts_per_du * v_du;
              i = amps_per_du * i_du;
      
              // Calculate power
              p_new = v * i;
              
              // Decide whether to increase or decrease duty cycle.
              // If power now is greater than power on previous cycle,
              // then keep going in the same direction. If power now
              // is less than on previous cycle, change direction.
              if (p_new < p_old)
              {
                  direction = -direction;
              }
              
              // Remember this power value for comparison on the next cycle
              p_old = p_new;
              
              // Increase or decrease the duty cycle
              duty_cycle = duty_cycle + (direction * step);
              PDC1 = duty_cycle * 2 * PTPER;
              
              // To assist debugging, print current values over serial link
              printf("v=%.2f i=%.2f p=%.2f dc=%.2f\n", v, i, p_new, duty_cycle);
              
              // This delay can be modified to control the rate
              // at which the duty cycle is updated.
              // I've set it to 100ms, but that's a complete guess.
              __delay32(3000000);
          }
      }
      
      // This function reads a single sample from the specified
      // analog input. It should take less than 5us when the
      // microcontroller is running at 30 MIPS.
      // The dsPIC30F4011 has a 10-bit ADC, so the value
      // returned is between 0 and 1023 inclusive.
      unsigned int read_analog_channel(int channel)
      {
          ADCHS = channel;          // Select the requested channel
          ADCON1bits.SAMP = 1;      // Start sampling
          __delay32(30);            // 1us delay @ 30 MIPS
          ADCON1bits.SAMP = 0;      // Start Converting
          while (!ADCON1bits.DONE); // Should take 12 * Tad = 3.2us
          return ADCBUF0;
      }
      

      Hope that helps.
      Ted

      • Degratia says:

        Hello Sir,
        I am getting an error saying : error: conflicting types for ‘read_analog_channel’, I would like to use this code for my mppt project. The input voltage is 84 and should be matched by changing the duty cycle in order to get maximum power.

  61. Võ Văn Tú says:

    Dear mr,
    I’m working on my Final Project. I have to interface ADE7753 with 30f4011 .
    I knew that i have to use SPI.
    Can you give me some code?
    Thanks!

  62. Mohamed Saleck Heyin says:

    salut
    Je veux que vous m’aider à trouver le code qui peut traiter la FFT d’un signal électrique tension et courant de fréquence 50Hz j’ai une carte dsPICDEM2 sur lequel je veux faire cette application puisqu’elle contient la famille dspic30f j’ai dspic30f4011 et dspic30f4013 particulièrement

  63. Reshmi says:

    Hai Ted,
    I need to generate six pwm signals each phase shifted as follows(alpha, alpha+180, alpha+120, alpha+120+180, alpha+240, alpha+240+180). I need these pulses for switching on the thyristors. so i have used interrupts for my program.
    INT1 = For shifting between the firing angles.
    INT2 = For detection of ZCD pulses.
    T1,T2, T3 interrupts for generating pulses with the desired delay.
    I have written code which generates all the six pwm pulses at the same instant. I am using dspic30f3011.
    Kindly help me for generating the pwm pulses which are phase shifted as said above.
    This is my code.
    # include
    # include
    #include

    void __attribute__((__interrupt__))_INT1Interrupt(void);
    void __attribute__((__interrupt__))_INT2Interrupt(void);

    int Firing_angle[]={3469, 3644, 3819, 3988, 4169, 4338, 4513, 4688};
    int Firing_angle1[]={3476, 3651, 3826, 3995, 4176, 4345, 4520, 4695};
    int Firing_angle2[]={3482, 3657, 3832, 4001, 4182, 4351, 4526, 4701};
    int i=0,flag=1;

    int main()
    {
    PWMCON1 = 0x00FF; // Enable all PWM pairs in complementary mode
    PTCON= 0x0001;
    PTCONbits.PTCKPS = 1; // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 0xffff;
    PTMR = 0; // Clear 15-bit PWM timer counter
    PTCONbits.PTEN = 0; // Enable PWM time base

    T1CON = 0x0010;
    T2CON = 0x0010;
    T3CON = 0x0010;

    IEC0bits.T1IE = 1;
    IFS0bits.T1IF = 0;
    IEC0bits.T2IE = 1;
    IFS0bits.T2IF = 0;
    IEC0bits.T3IE = 1;
    IFS0bits.T3IF = 0;

    PR1 = Firing_angle1[0];
    PR2 = Firing_angle[0];
    PR3 = Firing_angle2[0];

    T1CONbits.TON = 0;
    T2CONbits.TON = 0;
    T3CONbits.TON = 0;

    IEC1bits.INT1IE = 1;
    IFS1bits.INT1IF = 0;
    INTCON2bits.INT1EP = 0;
    TMR1=0x0000;
    TMR2=0x0000;
    TMR3=0x0000;
    IEC1bits.INT2IE = 1;
    IFS1bits.INT2IF = 0;
    INTCON2bits.INT2EP = 0;

    while(1)
    {
    PDC1 = 75;
    PDC2 = 75;
    PDC3 = 75;
    }

    }
    //INT1 to switch between the firing angles
    //INT2 to switch between the zcd
    void __attribute__((__interrupt__)) _INT2Interrupt(void)
    {
    if(flag==1)
    T1CONbits.TON=1;
    T2CONbits.TON=1;
    T3CONbits.TON=1;
    IFS1bits.INT2IF = 0;
    flag=0;
    }

    void __attribute__((__interrupt__)) _T2Interrupt(void)
    {
    T2CONbits.TON=0;
    IFS0bits.T2IF = 0;
    PTCONbits.PTEN = 1; // Enable PWM time base
    PWMCON1bits.PEN1L = 1;
    PWMCON1bits.PEN1H = 1;
    }

    void __attribute__((__interrupt__)) _T1Interrupt(void)
    {
    T1CONbits.TON=0;
    IFS0bits.T1IF = 0;
    PTCONbits.PTEN = 1; // Enable PWM time base
    PWMCON1bits.PEN2L = 1;
    PWMCON1bits.PEN2H = 1;
    }

    void __attribute__((__interrupt__)) _T3Interrupt(void)
    {
    T3CONbits.TON=0;
    IFS0bits.T3IF = 0;
    PTCONbits.PTEN = 1; // Enable PWM time base
    PWMCON1bits.PEN3L = 1;
    PWMCON1bits.PEN3H = 1;
    }

    void __attribute__((__interrupt__)) _INT1Interrupt(void)
    {
    flag=1;
    i++;
    if(i==8)
    i=0;
    PR1 = Firing_angle1[i];
    PR2 = Firing_angle[i];
    PR3 = Firing_angle2[i];
    IFS1bits.INT1IF = 0;
    }

  64. Ben says:

    sir how to measure phase angle of current using dspic30f2010. could you please help me generate the code

  65. Ranjithh says:

    Sir help me to generate SPWM waveform in DsPic30f4011. I tried it using matlab/simulink to generate a sinusoidal (reference) waveform and i have sampled it. i used these reference values to compare with the triangular waveform to produce a SPWM waveform using mplab. But still i couldnt achieve the perfect 50 Hz waveform . Please do help! 🙂

  66. TIEN LE says:

    Hi Mr.Ted
    Can you please make a simple code for CAN module of dsPIC30F4011 ?
    thank you so much !

  67. shailendra says:

    HELLO MR. TED
    I am using dspic30f4012 and i want to rotate my pmdc motor clockwise and anticlockwise simulatneously by 180 degree means it must start from 0 to 180 degree then return from 180 to 0 degree and this process must be continuous.I tried with a simple code but the problem is it rotates much in anticlockwise direction than clockwise. so please try to resolve my problem and post a progamme for bidirectional rotation of pmdc motor. i will be very thankful to you.

    • batchloaf says:

      Hi Shailendra,

      If you’re using a permanent magnet DC motor and you wish to control the angle accurately, you really need to use some form of feedback that tells the microcontroller what angle the motor is at. Typical approaches include attaching a potentiometer to the motor and using the changing resistance to sense the angle. However, since you only need to move to two specific positions (0 and 180) something simpler might be sufficient. For example, you could use something like a limit switch at each end of the range of motion to tell the microcontroller when the motor has arrived at the target position. Alternatively, you could use something like a TCRT5000 colour sensor to detect when the motor has arrived at the target angle. TCRT5000 colour sensors can be purchased very cheaply (about 20 cent the last time I ordered them) so it wouldn’t add a lot to the cost of the system.

      Without some kind of feedback, the only thing you can do is turn the motor on for a specific length of time and hope ot moves about 180 degrees. Doing it like that will never be accurate though.

      In most cases, when people want to control position (in this case the motor angle) accurately, they use a servo motor. You can get a cheap servo for $5 – $10 and then you control the angle by sending it digital pulses of a specific duration. Most commonly, 1ms pulses move the servo motor to 0 degrees and a 2ms pulses move it to 180 degrees. Pulse widths between 1ms and 2ms give you any angle between 0 and 180 degrees.

      Ted

  68. Gohar Abbas says:

    Hello Mr. Ted
    sir i need a ADC program for pic30F4011.
    My project is Sensorless Speed Control of DC Motor

  69. Aemika says:

    Dear Ted,
    I am sorry to post n irrelevant question w.r.t this blog.Could it be possible you have any information related to dspic33F family controllers? Because I would wish to have some queries clarified in that case.
    Regards,
    Aemika

  70. Gamez says:

    Greetings, I’m from Mexico and I want to ask you about a program that I need. I want to make the activation of a trifasic inverter with 6 IGBT’s through the PWM of the DSPIC30F4011, will you have an example of how to do this?

  71. Pingback: Introduction to robotics module – Laurence Keighery

  72. Parvathy says:

    Hai……..
    Please help me to generate a code for matrix multiplication and matrix inverse
    using dsp.h

  73. ram says:

    Hii sir. I am Ram. I need to control dspic30f4011 Motor control PWM of 20kz for 20MHz clock frequency. I need a control duty ratio by varying analog voltage input. Can u please any give me the code?

  74. HASAN METİN says:

    Merhaba Benim 30f4011 ile 2 adet servo motor kontrolü yapmam lazım ldr ile ışıga yönelmesi lazım yardımcı olabilirmisiniz acaba??

  75. mohan khedkar says:

    Hello sir, this is very usefu but i want to know how to generate pwm waveform by using MCC configurator in mplab for dspic33ep512mu810 controller.

  76. Sunday says:

    you are doing great. pls which of the sinewave inverter code using hbridge driver and dspic30f4011 should i use if i want stable 220vac output even if i put load on it?

  77. Hii
    i am using dspic30f3011 read the ADC value But this Code Not working any help
    /*
    * File: adc.c
    * Author: tec santosh kumar
    *
    * Created on 29 March, 2022, 11:36 AM
    */
    #include “inc/delay.h”
    #include
    #include
    #include
    #include “inc/adc.h”
    uint16_t ASAM;
    void adc_init(void)
    {
    ADPCFG = 0xFFFF;
    ADCON1 = 0x0000;
    ADCHS = 0x0002;
    ADCSSL = 1;
    ASAM = 1;

    ADCON1bits.ADON = 1;
    }

    int adc_read(ADC_Channel_t ch)
    {
    ADCON1bits.SAMP = 1; // start sampling …
    ADCON1bits.SAMP = 1;
    ADCON1bits.SAMP = 1;
    __delay_ms(200); // for 200 mS
    ADCON1bits.SAMP = 0; // start Converting

    while (!ADCON1bits.DONE){
    return ADCBUF0;
    }
    }

    thank you
    tec santosh kumar

    • batchloaf says:

      Hi Tec,

      It’s a while since I’ve looked at this, so I can’t remember what all the correct register settings are, but one thing I can see that looks wrong in your code is: This bit…

      while (!ADCON1bits.DONE){
      return ADCBUF0;
      }

      …should probably be this…

      while (!ADCON1bits.DONE);
      return ADCBUF0;

      The reason for using a while loop there is that you have to wait while the ADC completes its conversion before taking the final value from the ADCBUF0 register. However, the way you have it will return _immediately_ because you put the return statement inside the loop, whereas it should be after the loop.

      Hope that helps!
      Ted

Leave a reply to John Cancel reply