Monday, February 8, 2016

dsPIC30F Blink LED

I needed to get up to speed fast on how to add a timer interrupt for an imporved blink routine for the LED hanging off of my microchip dsPIC30F4012 PIC. I planned to make something fancy, but first I just needed to figure out whether there were timer interrupts in this PIC (there are, in fact there are five, and they appear on the block diagram on the datasheet), how to configure them in my C program, and whether some where better than others to use. The last question hasn't been answered for me yet, there are hints that the first timer might be different, maybe that it is directly driven by the system clock and the other ones might be driven by the instruction clock, but at this point I don't care because all of the examples that I found online used the first timer and so that was what I used.

Here are the links that I pored over to get enough examples that I was able to build my own code. The hard part was figuring out what applied to my particular PIC and what was for a PIC that was sufficiently different that I couldn't use it:

This is a nice tutorial in that an LED blinker is first shown as terrible code (piles of for loops to create a delay), then an interrupt handler. However, for some reason the author seems to be using the interrupt handler to time the delay which seems odd since the LED blink code could well have just been in there too.http://www.electronics-base.com/projects/complete-projects/195-microchip-microcontroller-dspic30f4013-blink-led-example-using-timer-complete-project

The original question in this forum thread is hilariously badly written, and the answers are all also bad except for one, which is full of wisdom. It's also not for my PIC: http://www.microchip.com/forums/m840532.aspx

This is probably the best example; although not exactly like what I wanted to do, it's for a PIC30F, it shows setup code for the timer, it explains about the prescaler and other built-in settings and how to use them. It also shows blinks both with a timer interrupt and in a simple loop using the delightful __delay32 function which I immediately also read up on: https://batchloaf.wordpress.com/2012/04/12/simple-timer-1-interrupt-example-for-the-dspic30f4011/

Here's another post by the same guy that did the one above; it has the blink example in it, but more importantly it has a ton of stuff about setting up programming (albeit with a much earlier version of the IDE): https://batchloaf.wordpress.com/dspic30f4011_super_example/

Here's a little bit more about __delay32(): http://www.microchip.com/forums/m486992.aspx

here's another nice example, just an LED blinker using a timing interrupt, with another person's example of using all the setup parameters for the timer: https://batchloaf.wordpress.com/2010/12/05/timer-1-interrupt-example-for-the-dspic30f4011/

Here's a whole reference manual just for the PIC30 timers, but it's so wordy that I just couldn't fight through to any answers about what was different about the different timers! Also all of their example code is in assembly, which is only a little helpful for my need to do this in C: http://ww1.microchip.com/downloads/en/DeviceDoc/70059D.pdf

The first example in this very professional-looking tutorial is another LED blinker using Timer 1. All of the examples that I found used Timer 1. There was information about how it's possible to join Timers 2&3 or 4&5 to make 32-bit counter/timers, which made me wonder what happens if that's not what you want to do, another question about the other timers that I was too rushed to find the answer to: http://www.mikroe.com/chapters/view/52/chapter-4-timers/

Here's something that I found while trying to learn if the other timers get the system clock or the instruction clock. The question is actually about a PIC33, but for some reason one of the commenters thinks that it's about the PIC30 and answers accordingly. However, it is unclear once again if his answer applies only to the first timer or all of them: http://www.microchip.com/forums/m156502.aspx

Here's an example for a Timer 2 module, but it's for a PIC16, so is only slightly helpful for my case: http://www.pcbheaven.com/picpages/The_Timer_Modules_Timer2/

Another PIC16 Timer2 example. This one is interesting because it shows a IDE utility called "Code Configurator" which might be helpful to learn how to use: http://microchip.wikidot.com/8bit:mcctimer2

Some test slides from an online class that start some examples for a PIC30F: http://academic.eng.au.edu/~nott/nott/MicroClass/Lectures/7.pdf

A powerful collection of timer examples, including setup of a PIC30F timer2/timer3 combination to blink an LED, although I'm not sure why a 32 bit counter would be needed for a .5Hz blink: https://www.pantechsolutions.net/project-kits/user-guide-programming-in-c-for-dspic30f4011

Some nice timer and interrupt examples, but for a PIC24: http://www.kibacorp.com/First%20Experiments%20Part%202.pdf

Here is my final C code. It's fancy; the objective was to have a slow blink pattern with an option for triggering a single fast blink. I created a 8Hz timer interrupt and then used globals to count through a 64-state counter, defining the slow blink on as the lower 32 states and the slow blink off as the upper 32 states. If the timer interrupt wakes up and a request for a fast blink ("activity_request") is set, it figures out what the last on/off state was, then either starts on a series of interrupt-driven states that turn the LED off, then on, then off, or if it was already off it just turns it on and off. The resulting visual effect is exactly what I was looking for.
int timer_counter = 0;
int activity_lead_off = 0;
int activity_on = 0;
int activity_request = 0;
int led_is_on = 0;

// Timer 1 interrupt service routine for LED blinking algorithm
void __attribute__((__interrupt__, __auto_psv__)) _T1Interrupt(void)
{
if (activity_lead_off == 1){
SetLed();
led_is_on = 1;
activity_on = 1;
activity_lead_off = 0;
} else if (activity_on == 1) {
ClearLed();
led_is_on = 0;
activity_on = 0;
} else if (activity_request == 1) {
activity_request = 0;
if (led_is_on == 1){
ClearLed();
led_is_on = 0;
activity_lead_off = 1;
} else {
SetLed();
led_is_on = 1;
activity_on = 1;
}
} else {
if (timer_counter < 32){

SetLed();
led_is_on = 1;
} else {
ClearLed();
led_is_on = 0;
}
}
if (timer_counter < 63) {

timer_counter++;
} else {
timer_counter = 0;
}
// Clear Timer 1 interrupt flag
_T1IF = 0;
}

void SetActivity()
{
if (activity_on == 0) {
activity_request = 1;
}
}


int main()
{
// Initialize Timer 1 for 8 calls/second
// PR1 AND tckps ARE SET TO CALL INTERRUPT EVERY 125ms
// Period = PR1 * prescaler * Tcy.
// Some documentation indicates that Tcy is crystal clock period
// Clock crystal is 7.3728MHz, Tcy = 135.633 nsec
T1CON = 0; // Clear Timer 1
T1CONbits.TCKPS = 3; // Set Timer 1 Prescaler 1:256
PR1 = 3600; // Set Timer 1 Period
_T1IP = 1; // Set Timer 1 interrupt priority
_T1IF = 0; // Clear Time 1 interrupt flag
_T1IE = 1; // Enable Timer 1 interrupt
T1CONbits.TON = 1; // Turn on Timer 1

.
.
.

}