Trouble Implementing Interrupts on MC9S12DT256
‎02-11-2008
02:27 AM
3,839 Views

batgirl
Contributor I
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, I am working with the MC9S12DT256 on the CSM12D development board and am having trouble with implementing interrupt routines. The first thing I did was alter the vector table by naming the entry associated with the Enhanced Capture Timer Ch7: TC7x. Then, I added the following routine to my main file using a sample file from Freescale as a guideline:
#pragma CODE_SEG __NEAR_SEG NON_BANKED //JCB interrupt
void TC7x(void)
{
if (TFLG1 == 0x80)
{
MOTOR1_RUN_FLAG = 0;
}
}
#pragma CODE_SEG DEFAULT
MOTOR1_RUN_FLAG is toggled to the interrupt state when a touch sensor is depressed. This works fine, but the problem lies when resetting the flag... The code will enter the interrupt routine but will not proceed beyond the conditional statement. It freezes there, and I am not sure why. I am also not too sure what the #pragma directives are doing. Any insight into this problem would be much appreciated. Thanks in advance.
#pragma CODE_SEG __NEAR_SEG NON_BANKED //JCB interrupt
void TC7x(void)
{
if (TFLG1 == 0x80)
{
MOTOR1_RUN_FLAG = 0;
}
}
#pragma CODE_SEG DEFAULT
MOTOR1_RUN_FLAG is toggled to the interrupt state when a touch sensor is depressed. This works fine, but the problem lies when resetting the flag... The code will enter the interrupt routine but will not proceed beyond the conditional statement. It freezes there, and I am not sure why. I am also not too sure what the #pragma directives are doing. Any insight into this problem would be much appreciated. Thanks in advance.
8 Replies
‎02-11-2008
07:36 AM
1,186 Views

JimDon
Senior Contributor III
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, there are a couple of problems.
First, you need to declare the function as an interrupt handler.
- You don't need to test the bit because if you got here, you know that timer 7 interrupted.
You would only test this bit if you used the same handler function for more that one timer.
- You need the interrupt key word to tell the compiler that this is an interrupt handler and it should generate an RTI instruction to return and other special code.
- You probably don't need the pragma unless you are using banked memory, as interrupt handlers must not be in banked memory and the pragma forces the routine into non banked memory.
- If you don't set the TC7 register, you will not get another interrupt until the "16 bit counter" rolls over again. The code shown sets the channel to interrupt again t7delay counts in the future.
- Writing to TFLG1 clears the interrupt and must be done unless you set the TFFCA bit in the TSCR1 register (bit 4), in which case writing to TC7 will clear the interrupt. Do NOT or this bit as it is special and this code will not disturb other channels.
Look over S12ECT16xxx.pdf to understand how this all works.
For whats its worth, this is my set up code.
Message Edited by JimDon on 2008-02-11 01:48 AM
First, you need to declare the function as an interrupt handler.
Code:
__interrupt void TC7x(void) { // minimum timer interrupt handling code. // You really don't need to test this bit. TFLG1 = 0x80; // Clear the interrupt. TC7 += t7delay; // reset the register, if you want a specific rate. // This also resets the interrupt if you set the TFFCA bit.}
- You don't need to test the bit because if you got here, you know that timer 7 interrupted.
You would only test this bit if you used the same handler function for more that one timer.
- You need the interrupt key word to tell the compiler that this is an interrupt handler and it should generate an RTI instruction to return and other special code.
- You probably don't need the pragma unless you are using banked memory, as interrupt handlers must not be in banked memory and the pragma forces the routine into non banked memory.
- If you don't set the TC7 register, you will not get another interrupt until the "16 bit counter" rolls over again. The code shown sets the channel to interrupt again t7delay counts in the future.
- Writing to TFLG1 clears the interrupt and must be done unless you set the TFFCA bit in the TSCR1 register (bit 4), in which case writing to TC7 will clear the interrupt. Do NOT or this bit as it is special and this code will not disturb other channels.
Look over S12ECT16xxx.pdf to understand how this all works.
For whats its worth, this is my set up code.
Code:
TSCR1 = 0x90; // Enable TCNT and fast clear TSCR2 = 0x03; // Set prescaler to 1:8 (or what you need) TIOS |= TIOS_IOS7_MASK; // Enable OC7 TC7 = TCNT + t7delay; // Init the compare registers TIE |= TIOS_IOS7_MASK ; // Enable the timer interrupt bit.
Message Edited by JimDon on 2008-02-11 01:48 AM
‎02-11-2008
10:40 PM
1,186 Views

batgirl
Contributor I
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your quick replies. I have made the changes you suggested in my code, but am still having a problem. I am setting up the enhanced capture timer bit with the following settings.
Then implementing the following function that controls the motors. It should run a stepper motor as long as both conditions are met (that PB2 has not been pressed and as long as the MOTOR1_RUN_FLAG (a global unsigned int) equals 1). The interrupt routine just toggles the channel bit back and sets the MOTOR1_RUN_FLAG so that the motor no longer runs.
So when the code is run, the motor will stop when PB2 is depressed or the interrupt goes high. When running the code, it gets hung up with in the routine when the interrupt condition is met. During debug mode if a breakpoint is set inside the interrupt routine, the code can be stepped through like a normally functioning program. The debug mode simulates the code correctly, but during realtime it always gets hung up within that routine. Should there be a return to sender command like there is in Assembly? I haven't found anything like that in sample code, but I could be mistaken. Or Is there just a better option for interrupts than the enhanced capture timer? I guess there could always be the case where someething simply is completely missing from my code. Thanks again for your help.
Message Edited by batgirl on 2008-02-11 10:08 PM
Code:
TSCR1 = 0x90; TSCR2 = 0x02; TIOS = 0x01; TCTL2 = 0x02; //interrupt stuff TCTL3 = 0x80; TIE = 0x80;
Code:
void Motor_Run(unsigned int motor_dir) { if(motor_dir == 0) PORTB_BIT0 = 0; else PORTB_BIT0 = 1; TC0 = TCNT + PULSE; MOTOR1_RUN_FLAG = 1; while (PBMCUSLK_PB2 && (MOTOR1_RUN_FLAG == 1)){//run motor until pushed or interrupt while (TFLG1_C0F == 0){} TCTL2 = 0x03; TC0 = TC0 + PULSE; while (TFLG1_C0F == 0){} TCTL2 = 0x02; TC0 = TC0 + PULSE; } return; } #pragma CODE_SEG __NEAR_SEG NON_BANKED //JCB __interrupt void TC7x(void) { TFLG1_C7F = 1; MOTOR1_RUN_FLAG = 0; } #pragma CODE_SEG DEFAULT
Message Edited by batgirl on 2008-02-11 10:08 PM
‎02-11-2008
11:15 PM
1,186 Views

JimDon
Senior Contributor III
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
How is the stepper motor connected? That is to what pins.
If it is a stepper motor, you need 2 phases, or is it the kind you just pulse to get a step?
I'll assume that PULSE is the amount of time you need to pulse the motor.
After you explain this, we can help you.
Your code for TC7 looks fine. But of course since you decided not the set the TC7 register, it will interrupt at some random point.
It does not seem right to just stop the motor when the tc 7 interrupt happens. Also
You just added the vector table. At first glance it look fine.
Message Edited by JimDon on 2008-02-11 05:18 PM
If it is a stepper motor, you need 2 phases, or is it the kind you just pulse to get a step?
I'll assume that PULSE is the amount of time you need to pulse the motor.
After you explain this, we can help you.
Your code for TC7 looks fine. But of course since you decided not the set the TC7 register, it will interrupt at some random point.
It does not seem right to just stop the motor when the tc 7 interrupt happens. Also
TFLG1_C7F = 1; // read/write to do an or. or's the bit, and you are not supposed to that. It should be just as I had it: TFLG1 = 0x80; // Clear the interrupt.
As I said, this is a special register and writing a 1 in the bit position of the channel will not affect other channels. If the motor is going the be hooked up to the output if timer channel 0 then you should set it up for output compare toggle mode and write an interrupt handler for that. This will cause a square to be generated on the pin. It' very simple to do. If this is what you want, I will post some sample code for that.
You just added the vector table. At first glance it look fine.
Message Edited by JimDon on 2008-02-11 05:18 PM
‎02-12-2008
01:14 AM
1,186 Views

batgirl
Contributor I
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The stepper motor is connected via a driver card that requires two inputs: step and direction. The step line is just constantly pulsed using the PT0 output pin, and the direction is controlled by a PORTB_BIT0. The stepper motor control works fine.
The motor control is currently operated by pushbuttons just to verify its functionality. Later it will be expanded to be controlled via the serial port. The current goal is to stop the motor via an interrupt signal produced from a touch sensor (an input detected on tc7 port). Our output from the sensor is working, but when the microcontroller receives that pulse it gets stuck in the interrupt routine (unless we are in debug mode as mentioned in the previous post).
I have changed the interrupt routine from
TFLG1_C7F = 1;
to
TFLG1 = 0x80;
but the same problem results. I will attach my main file along with other relevant files so that hopefully it will make more sense. Thanks again. I really appreciate your help.
The motor control is currently operated by pushbuttons just to verify its functionality. Later it will be expanded to be controlled via the serial port. The current goal is to stop the motor via an interrupt signal produced from a touch sensor (an input detected on tc7 port). Our output from the sensor is working, but when the microcontroller receives that pulse it gets stuck in the interrupt routine (unless we are in debug mode as mentioned in the previous post).
I have changed the interrupt routine from
TFLG1_C7F = 1;
to
TFLG1 = 0x80;
but the same problem results. I will attach my main file along with other relevant files so that hopefully it will make more sense. Thanks again. I really appreciate your help.
‎02-12-2008
02:15 AM
1,186 Views

JimDon
Senior Contributor III
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, first of all, to run the motor we are going to do things a but differently. If I have understood you. the step pulse is connected to the PT0 pin which is the output for the timer channel 0. We are going to generate a square wave on the pin using output compare toggle mode. We will turn this on when we want to motor to step and off when we do not. You will be using timer channel 7 later, but for now lets just worry about getting the motor drive right.
I have used this exact code many times, so I assure it will produce a square wave and the on/off macros will work.
Just try this - turning the motor on and letting it run for a bit then turning it off.
You see, separating the pieces of the project and attacking them individually is how you do it.
Once you have assured your self that the motor run code is perfected, then worry about the touch switch (which you may discover has it own problems).
If you want, make a test project. This is a good idea, because later if things go crazy on you, you can always come back and try things. I do this all the time. Copy over your vector table and anything else you
need. If fact you can just clone your current project and change it..
Code:
// near the top of the file Add this: // Enable channel 0 interrupts. #define MOTOR_ON() TC0 = TCNT + PULSE; TIE |= 1 // Disable channel 0 interrupts. #define MOTOR_OFF() TIE &= ~1 int StepCounter = 0; // for testing, may be useful later. // In main: (other thing in main you need) //interrupt stuff TSCR1 = 0x90; // Enable TCNT and fast clear TSCR2 = 0x02; // Set the prescaler // Withe the TIE, TCTLX and TOS registers, we DO need to 'or' things in // 'and' and things out. TIOS |= 0x01; // set channel 0 to output compare TCTL2 |= 0x01; // set channel 0 for toggle mode. // forget about channel 7 for now... EnableInterrupts; // Don't do this until you have things set up right.. DDRB_BIT0 = 1; //set pin for output PORTB_BIT0 = 0; //start out with pin at 0 MOTOR_ON(); // Start channel 0 interrupts // Let the motor run for 100 steps then stop it. // After this works, change the code to step in one direction, // then step in the other direction for so many pulses. for(;;) { if( StepCounter > 100 ) // change 100 if this is too short or long. MOTOR_OFF(); } } // end main // Make sure you add this to the vector table in the slot for // timer channel 0. __interrupt void Timer0Interrupt(void) { ++StepCounter; TC0 += PULSE; // update the register and clear the int. }
Message Edited by JimDon on 2008-02-11 08:17 PM
Message Edited by JimDon on 2008-02-11 08:19 PM
‎02-12-2008
06:14 AM
1,186 Views

batgirl
Contributor I
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Although our previous code controlled a stepper motor, yours is much better because it will allow for multiple motor control relatively easily. We were able to use your code with the PortP interrupt to successfully stop the motor. Perhaps there was an issue with using the timer control registers. I am not sure, but am very grateful for all the help you have provided. Thanks once more.
‎02-12-2008
02:35 PM
1,186 Views

JimDon
Senior Contributor III
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, all I did is show you how Freescale intended to hardware to be used.
There was another big problem with how you were doing things - the code would be looping around consuming 100% of the cpu time attempting to do a real time task.
It's ok to loop around in some places, but that was a "tight" loop that due to it's purpose could not do much else.
The for(;
loop in main is the called the foreground task, where as the interrupt in considered the background task. The way you are doing things now, the motor control task only takes nanoseconds, no more that a few percent of the cpu time. Also the motor control work will preempt the foreground task, so it does not matter that it is just looping around, because the time critical work will happen as it should.
It is ok to do things in the foreground task, like testing if the switch had been pushed and turning the motor off, because now your time critical work is on an interrupt thread, and the pushing of a switch is not time critical as to when the motor goes off.
If you haven't already considered this, changing the value of PULSE will control how fast the motor steps.
Good luck on the rest of your project - if you have more questions we will be here - same bat time same bat channel.
There was another big problem with how you were doing things - the code would be looping around consuming 100% of the cpu time attempting to do a real time task.
It's ok to loop around in some places, but that was a "tight" loop that due to it's purpose could not do much else.
The for(;

It is ok to do things in the foreground task, like testing if the switch had been pushed and turning the motor off, because now your time critical work is on an interrupt thread, and the pushing of a switch is not time critical as to when the motor goes off.
If you haven't already considered this, changing the value of PULSE will control how fast the motor steps.
Good luck on the rest of your project - if you have more questions we will be here - same bat time same bat channel.
‎02-11-2008
08:21 AM
1,186 Views

Lundin
Senior Contributor IV
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Alternative syntax to the __interrupt keyword:
#pragma CODE_SEG __NEAR_SEG NON_BANKED //JCB interrupt
#pragma TRAP_PROC
void TC7x(void)
...
Neither method is ISO C, as interrupts aren't covered by the standard.
#pragma CODE_SEG __NEAR_SEG NON_BANKED //JCB interrupt
#pragma TRAP_PROC
void TC7x(void)
...
Neither method is ISO C, as interrupts aren't covered by the standard.
