how to properly configure the PIT for the 9S12XDP512?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

how to properly configure the PIT for the 9S12XDP512?

6,037 Views
thesheriff
Contributor I
I am trying to set up the Periodic Interrupt Timer for channel 0 so that every 1 sec. the cpu is interrupted. After pouring over documentation and online forums, I still cannot make it work. I believe that I understand how the PIT works, and how to set up interrupt vectors, but I can not understand what I am doing wrong. Below is my code, written with CodeWarrior 4.5:

/* PRM file */
VECTOR ADDRESS 0xFF7A DTYISR

/* ASM file */
XDEF Entry, main, DTYISR

; code section
MyCode: SECTION
main:
Entry:
LDS #__SEG_END_SSTACK ; initialize the stack pointer
CLI
; PORTA is connected to LEDs which helps me determine if the ISR was called
MOVB #$FF, DDRA  ; set PORTA as output
MOVB #$FF, PORTA ; turn on the LEDs
MOVB #$01, DDRP ; set PORTP[0] as output
Loop0:
MOVB #$70, INT_CFADDR ; point to the interrupt jump vector containing the PIT channels
MOVB #$04, INT_CFDATA5 ; set interrupt priority level 4 for vector $FF7A (PIT0)

MOVB #$01, PWMCLK ; set the PWM channel to use the scaled clock 
MOVB #$01, PWMPRCLK ; pre-scale the clock
MOVB #$0A, PWMSCLA ; scale the pre-scaled clock
MOVB #$A0, PWMPER0 ; set the PWM period
MOVB #$50, PWMDTY0 ; set the PWM duty cycle
MOVB #mPWME_PWME0, PWME ; enable PWM channel 0
LDAB #$50
STAB PWMDTY0 ; the PWM result is a 1250Hz square wave, 50% duty cycle

MOVB #$FF, PITMTLD0 ; set the micro timer value
MOVW #$F424, PITLD0 ; set the timer counter
MOVB #$00, PITMUX ; set the mux to use channel 0 (for completeness)
MOVB #$01, PITCE ; enable PIT channel 0
MOVB #$01, PITINTE ; enable interrupts for channel 0
MOVB #$80, PITCFLMT ; finally, enable the PIT module
Loop1: BRA Loop1

DTYISR:
ADDB #$30 ; I realize that AccB gets pushed onto the stack before the PC points to the ISR, but this is just a test
STAB PWMDTY0 ; update the duty cycle
CLR PORTA ; turn off PORTA[7..0]
MOVB #$01, PITTF ; clear the PIT interrupt flag for channel 0
RTI
/* END */
I have seen other similar posts on the forum, and I have applied some of those solutions to my problem, but nothing has worked. However, there is one that I don't understand, and I wonder if it might apply to my problem? What is the purpose of the Pull-Up Control Register (PUCR) and can it affect the behavior of interrupts?

Thanks for your help.

Labels (1)
0 Kudos
Reply
11 Replies

2,060 Views
Steve
NXP Employee
NXP Employee
Your algorithm appears to be ok for the PIT.
Have you checked what the CPU is doing using the debugger? Is it stuck at loop1 or is it going anywhere else? Your timeout is very long - depending on your bus clock it could be many seconds before you get an interrupt. Do you see the PIT flag being set? Is the IRQ pin causing an interrupt?
0 Kudos
Reply

2,060 Views
thesheriff
Contributor I
Thanks for your reply. It's good to know that I am configuring the PIT correctly. I do not have a BDM, so I have been using the Full-Chip Simulator for testing. The ASM example I posted did not interrupt when I ran it in the Simulator. So I re-made my project in C, created my own vector table from one of the CW examples, and then ran it in the Simulator, and the interrupts work. How reliable is the Simulator, anyway? Would the BDM be a better tool to debug interrupts?
 
Nevertheless, when I load my new C program to the controller, I get the same problem, no changes in output = no interrupts. I considered the fact that my timeout period is very long, so I have tried a few tests where I shortened it significantly, but that did not change any thing.
 
You mentioned the IRQ pin may be interrupting, and as I understand it, the IRQ has the highest priority of 7. So if the IRQ were interrupting, it would prevent any other interrupt from occurring, right? My documentation says the IRQ pin is active-low, so that means that I should put it HI to prevent an interrupt, right? Do I need to set the PUCR for PORTE if I want to do this?
 
Thanks for your help.
 
0 Kudos
Reply

2,060 Views
Steve
NXP Employee
NXP Employee
If it works on the simulator I would expect it to work on the hardware so maybe something else is going on. I would always recommend using BDM to debug since it accounts for all of the external influences in your design. The simulator is handy for trying out ideas and optimising small sections of code.
The IRQ should be held high to avoid causing interrupts so check what is connected there on your hardware. The PUCR for port E will be enabled by default so you shouldn't need to enable that unless you disabled it in your code.
You can also try catching other interrupts in a "catch all routine" to see if something else is hogging the processor (direct all interrupt vectors to a single routine")
0 Kudos
Reply

2,060 Views
thesheriff
Contributor I
Thanks for your help. Your debugging ideas helped me track down the problem. Now all I need is a solution. It turns out that when I load my image to the controller, the vector table is not updated to point to my interrupt routine. So no interrupts are being handled, at all! I tried loading my image with both uBug12x (from TechArts) and CW, but the same problem exists; incorrect address in the vector table. Could this be related to a jumper setting on the board (i.e. MODA=1, MODB=1)? Or maybe I need a better utility? Would a BDM resolve this issue?
 
Thanks again for your help.
 
 
0 Kudos
Reply

2,060 Views
Steve
NXP Employee
NXP Employee
Ah, MODA & MODB = 1 is an unusual mode to select. I wouldn't expect anyone except emulator manufacturers to use that mode. The internal flash may not even be present in that configuration. MODA and MODB should both be 0 if you intend to use the device in single-chip mode.
0 Kudos
Reply

2,060 Views
thesheriff
Contributor I
I checked the jumper settings and it is MODA=0, MODB=0, as best I can tell. Anyway, I still can not write to the vector table. I just don't understand why. Here is how I set up my interrupt table and routine:
 
Code:
/* main.c */#pragma CODE_SEG __NEAR_SEG NON_BANKEDinterrupt void DTY_ISR() { Counter--; PWMDTY0 = duty[ Counter ]; if( Counter == 0 ) {   Counter = 5; }  PITTF = 0x01;}#pragma CODE_SEG DEFAULTvoid main(void) {...}/* isr_vector.c */extern void near _Startup(void);       /* Startup routine */extern void near DTY_ISR(); #pragma CODE_SEG __NEAR_SEG NON_BANKED /* Interrupt section for this module. Placement will be in NON_BANKED area. */interrupt void UnimplementedISR(void){  /* Unimplemented ISRs trap.*/  asm BGND;}typedef void (*near tIsrFunc)(void);const tIsrFunc _vect[] @0xFF60 = {     /* Interrupt table */...DTY_ISR,                 /* vector 66 */       ..._Startup                          /* Reset vector */};

 
Every time I load it to FLASH, the vector table keeps its default values. I'm totally confused. I mean, how is it even restarting to 'main' if the reset vector points to $F800, instead of $C000?! Maybe it's a compiler setting? I dunno.
 
Thanks for your help.
 
(Alban: code format)

Message Edited by Alban on 2006-11-17 03:16 PM

0 Kudos
Reply

2,060 Views
Steve
NXP Employee
NXP Employee
I assume you mean the erased value of flash when you say default (0xFFFF)?
Check the .map file that CW creates to make sure your tIsrFunc _vect vector table is in memory and at the right address. If the code is being programmed ok and the vectors are not then something is probably missing in the object file which could point to a linker file problem but check the object file first.
0 Kudos
Reply

2,060 Views
thesheriff
Contributor I
I checked the .map file, and as far as I can tell, it checks out. It even lists my table as consuming 240 bytes, which adds up. I've been doing some more reading and I thought that I found a solution. How about moving my vector table to a writable address, say $CF10, and then after reset, set the IVBR to $CF? I tried this out in the simulator, worked no problem. I loaded my program to flash, double checked my vector table is at $CF10-$CFFF, and then ran it. No response.
 
I went back and disabled interrupts altogether, but kept my vector table at $CF10, and still no response. By response I mean the square wave I generate, which is not dependant on interrupts. Why would the controller care where I put my table? Should my vector table be located somewhere else in memory?
 
In case this helps, I am using uBug12x, from TechArts, to load my S19 file to flash. Could this utility be doing something that is hosing my attempts?
 
Thanks for your help.
 
 
0 Kudos
Reply

2,060 Views
thesheriff
Contributor I
AHA!! I got it!
 
For the sake of completeness, and anyone else that stumbles across this, here's how I did it.
 
I am using CWv4.5 w/ uBug12x for the Adapt9S12XDP512 MCU from TechArts (nice guys BTW).
 
Once a workspace is created in CW, open up the 'main.c' file. Add the following, before the 'main' routine:
 
/* Handlers */
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void DTY_ISR() {
 Counter--;
 PWMDTY0 = duty[ Counter ];
 if( Counter == 0 ) {
   Counter = 5;
 }
//  PWMDTY0 = 0xD0;
 PITTF = 0x01;
}
/*
 * dummit: dummy interrupt routine
 */
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void dummit(void)
{
  //_asm("BGND");
  //_asm("RTI");
}
/* Vector Table for S12X */
typedef void (*near tIsrFunc)(void);
const tIsrFunc _vectab[] @0xCF00 = {
 (void*)0xFFFF,  /* 0xFF00 backdoor key               */
 (void*)0xFFFF,  /* 0xFF02                            */
 (void*)0xFFFF,  /* 0xFF04                            */
 (void*)0xFFFF,  /* 0xFF06                            */
 (void*)0xFFFF,  /* 0xFF08                            */
 (void*)0xFFFF,  /* 0xFF0A                            */
 (void*)0xFFFF,  /* 0xFF0C                            */
 (void*)0xFFFE,  /* 0xFF0E security                   */
...
dummit,
DTY_ISR,           /* PIT0 */
dummit,
...
// _Startup   (don't need it)
};
 
OK, pause for explanation. It's important to add the first 8 interrupt vectors because the MCU finds the ISR based upon the base address of the vector and the interrupt that occured. In this case, I want to interrupt based on the Periodic Interrupt Timer Channel 0 (PIT0). So when an interrupt occurs, the MCU takes the base address and adds $7A to it (base + offset). So keep the first 8 elements to gaurantee the correct offset to the interrupt service routine.
 
Finally, add the following line within the 'main' routine, BEFORE calling 'EnableInterrupts':
 
IVBR = 0xCF;
 
This sets the base address of the interrupt vector to point to my new interrupt vector. Ah, the brilliance of relocatable vectors. Now Rock 'N' Roll!
 
As a special note, my real problem stemmed from setting the '_Startup' routine as part of my interrupt vector. This is bad for some reason. Anyone know why, cuz I don't?
0 Kudos
Reply

2,060 Views
Steve
NXP Employee
NXP Employee
It's great that you got it going but I just want to emphasise that you don't need to move the vector table to make it work. I suspect the problem was mainly having the wrong offsets in the vector table. The ISR needs to be in a near segment because the vectors are all 16-bit addresses.
If you want you don't need to include the first 8 words in the vector table you can simply tell the linker that the vector table has a different starting address with something like:
const tIsrFunc ResetVectorTable[] @0xFF10 =
 
The _Startup and other reset vectors must always be at FFxx because the IVBR is set to 0xFF after any of the three reset conditions. So these should always be placed at 0xFFFA to 0xFFFF.
 
Anyway, thanks for taking the time to tell us you got it working and what worked for you.

Message Edited by Steve on 2006-11-2010:51 AM

0 Kudos
Reply

2,060 Views
Alban
Senior Contributor II
Hi Sheriff,
 
Glad you got it working !
 
From looking at your code in the post, I wasn't able to see where _startup was.
This function should be your reset vector.
 
This function is initializing variables and the MCU (stack,...). It is not to be called during execution at anytime except after a reset.
 
After doing all its code, _startup is calling main().
 
Cheers,
Alban.
0 Kudos
Reply