Guys,
As I'm new to Embedded development, I've used the demo applications (Accelerometer, Temperature, Simple) for the MSP430-PAN1315, and have learned a feature at the time, while applying it to my application.
For the last two days I'm trying to figure out timers (I've successfully played with the TimerA1 supplied with the demo app), but I seem to miss imperative knowledge. I've looked at tens of posts, and looked at many code snippet, I understand the general way the timer works, but not the configurations available vs their implementation usage, I seem to get lost with all the indices, and parameters, which also do not correspond between TimerA0/TimerA1/TimerB...
I've read the User Guide, for Timer A, but it is too (HW) technical, is there a simple document I can read, which would elaborate the timer clock types vs their usage, and some code snippets with reasonable explanations of the code?
Thanks,
Adam.
Java Developer & ArchitectNu-Art Software
-----LinkedInTwitter-----
To be a good student, you must first be a good teacher.
Information about timers itself (TimerA, TimerB, TimerD) is found in the users guide. It explains all working modes and the registers.
The naming may be cinfusiong. On old MSPs, there was only one TimerA at max. So it simply was TimerA (TA). Later devices can have up to three TimerA modules, named TimerA0 to TimerA2.This is for the identificaiton in the code.
In the datasheets, however, a different naming is used. Since the enumeration of the tiemr modules is unimportant inthe datasheet, the numbe rbehind the A or B indicates the number of capture/compare units in this timer. If the datasheet reads 'One TimerB7' then there is one TimerB with seven CCR units.Same for the TimerA: having one TimerA3 and one TimerA2 means there is one TimerA module (likely TA0) with three and one (likely TA1, as it is listed as second) with two CCR units. However, the two are named TimerA0 and TimerA1 in the code. And probably the order is the same order as they appear listed in the datasheet.
If you're confused, well, you'r enot the only one. It even gets more complex with the interrupt vectors. Sicne each timer has two vectors, adn the naming can get quite confusing as the naming too changed with the existence of mroe than one TimerA in a device:
TIMERA0_VECTOR is the same as TIMER0_A0_VECTOR. But TIMERA1_VECTOR is the same as TIMER0_A1_VECTOR and both belong to TimerA0. Hoever, the second notation is only available on devices or device families which have more than one TimerA. TimerA1, however, has TIMER1_A0_VECTOR and TIMER1_A1_VECTOR.
_____________________________________Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.
http://processors.wiki.ti.com/index.php/Grace_Quick_Start_Guide?DCMP=Grace&HQS=Other+OT+grace#Welcome
I did not understand what Grace is for. Sounds like you may want to use it.
After closely reading your post, I've replaced TIMER1_A0_VECTOR with TIMER0_A0_VECTOR, and now I can debug the interrupts.
I have noticed this unusual behavior:
When I start the program with a breakpoint (IAR) in the interrupt, after a few runs the application restarts, I have no idea why... but if I disable the breakpoint and activate it after a while, it works fine. (I start the timers after all the application's modules/features have been initialized)
Also, what happens when an interrupt implementation exceeds the timer cycles defined? Is this even possible?
Adam ZehaviWhen I start the program with a breakpoint (IAR) in the interrupt, after a few runs the application restarts, I have no idea why...
You say you start the timers as the last thing, but that might be not exactly true, depending on your implementation.
Adam ZehaviAlso, what happens when an interrupt implementation exceeds the timer cycles defined? Is this even possible?
If the ISR executiojn tiem exceeds the duraiton ebtween two interrupts, there are two possibilities:
First, if you clear the interrupt flag at the start of your ISR (which is implicitely done for the TIMERx_A0 interrupt but must be manually done for all others by a direct clear operation or reading the interrupt vector register) then the next interrupt is already pending when you leave the ISR and it will enter immediately again. Bringing th emain code to a halt.If you clear the interrupt flag at the end of your ISR, you might have had an interrupt overflow already and clear the flagh for both interrupts, the one you served and the one which followed (as there is only one flag, you cannot tell), and you'll lose one interrupt.If the interrupts come periodically (which usually is the case for timers), then even in the first case, you'll eventually lose one interrupt. The sooner, the longer the ISR is.
So first rule for ISR programming: ISRs have to be fast in (which is done by the hardware) and fast out (which is done by putting only the absolutely necessary code into the ISR, setting global flags for longer tasks and let the main code act accordingly). The faster the better.
Thank you for a detailed response...
There another issue I'm really troubled by while implementing the other interrupt in my application, which again, is based on a combination of the demo applications came with the MSP430-PAN1315.
I'm working on a prototype, which is based on the msp430 256k, and have multiple HW components connected to some of its registers.
After adding my own interrupt, (which I assume done right, because I did get the interrupts and could control its cycles and all) I've started to experience weird register value changes... In this new interrupt, I've iterated on timed tasks, where each performs a different action, which involves writing values to registers.
To be more specific, there is a motor connected to P8-5, and when the register value set to high the motor is activated.
Upon launch, I've made sure that the value of that register is set to 0, (in debug I can see that its value is really 0) and for some reason, when the timed tasks code runs in the new interrupt, occasionally, the motor is been activated, and if to add some more gasoline to the fire, no other part of the code (except launch) do anything with the P8-5 reference I've defined and use. (I've search the entire code)
I've been trying, unsuccessfully, to understand this for long hours, and have decided to move the iteration of the timed tasks, to the original interrupt, which came with the demo application, and this never happen again.
For me this is nuts, but then again, I'm used to Java and a structured environment, what am I missing, what could this other interrupt do to the system, that it would start writing values to random registers?
I'm saying random registers, because I've noticed also other HW components registers values been changed, and I know that the motor register P8-5 was not activated every launch.
Thanks in advance,
What you describe shouldnot happen normally. However, there might be several reasons.
There's always a chance that the register view of the debugger is no up to date. It shouldn't, but since JTAG access is slow, there might be racing conditions with update and display etc.
Some registers of the MSP change their value caused by hardware events. However, the port registers (except for the PxIN and PxIFG registers) shouldn't.
Since all 8 port pins of P8 are controlled in one register byte, it may be that you accidentyally change P8.5 when you want to change a different port pin in P8. It's coding bug, but perhaps one that isn't recognized easily.
Also, using interrupts requires some second-thought on global variables: the compiler doesn't know that during execution of the main code an interrutp may magically change global variables. So the compiler may keep a copy of a global variable in a register and the program won't notice a change done by an ISR. The same way, writ access to a global variable might be delayed (because form the analyzed program flow nobody will be able to see the change) and the ISR won't see that the main program has already changed the variable. To avoid this, all variables that are use din both, main code an dinterrupt code, mus tbe declared volatile.The (intentional) drawback of volatile variables is that the compiler will generate exactly as many accesses to the variable as the source code tells. So use of bitfields on them is highly inefficient. (FYI: all hardware registers are treated as global variables too and are declared volatile as hardware may change the content unexpectedly.)
You should post your (non-working) code for further analysis if you want to know why exactly this was happening.
Adam ZehaviFor me this is nuts, but then again, I'm used to Java and a structured environment
I see you are quite busy answering questions here, so I appreciate you taking the time to answer mine as well.
Jens-Michael GrossThere's always a chance that the register view of the debugger is no up to date. It shouldn't, but since JTAG access is slow, there might be racing conditions with update and display etc.
I'm pretty sure this is not the case, since this action happens before any timer initialization, thus no race conditions...
Jens-Michael GrossSince all 8 port pins of P8 are controlled in one register byte, it may be that you accidentyally change P8.5 when you want to change a different port pin in P8. It's coding bug, but perhaps one that isn't recognized easily.
I have no business with any other part of the port 8, except for the motor bit 5, and the action is performed singularly on that bit, so this is not the case as well.
Jens-Michael GrossAlso, using interrupts requires some second-thought on global variables
I understand now the volatile necessity in these cases, but would moving the code from one interrupt to another require any changes in global variable volatile definition, I suspect not... also because now it works as expected and I didn't change any volatile definition.
Jens-Michael Grossseeing the quality of the work many todays 'software designers' (can't call them 'engineers' or such), I'm glad that many of them use Java for their own sake :)
I couldn't agree more... :)) but sometimes, that also doesn't help...
Jens-Michael GrossYou should post your (non-working) code for further analysis if you want to know why exactly this was happening.
OK... This is the code which caused the problem:
void onTimerInterrupted(void) { for (int i = 0; i < timerTasksCount; i++) { if (!timerTask[i].enabled) { continue; } timerTask[i].delayed += timer.dt;
if (timerTask[i].delayed < timerTask[i].delayInterval) { continue; }
timerTask[i].delayed = 0; timerTask[i].taskAction(); }}
void configTimerTask(int delayCycles, int dt) { timer.delayCycles = delayCycles; timer.dt = dt; TA0CCR0 = delayCycles; TA0CCTL0 = CCIE;}
void stopTimerTask(void) { TA0CTL &= ~MC_3;}
void startTimerTask(void) { TA0CTL = TASSEL_1 + MC_1 + TACLR;}
#pragma vector=TIMER0_A0_VECTOR__interrupt void TIMER_TASK_INTERRUPT(void) {
TA0CCTL0 &= ~CCIFG; __bis_SR_register(GIE);
onTimerInterrupted();}
NOTE, that when I moved the onTimerInterrupted(); call to the original interrupt, which came with the demo applications everything works just fine.
And yes, some of these should be a Macro...
Thank you for your time.
Sorry for the long delay.I hope you figured out what's going on in the meantime. If not, well, I found the timer to look at your code and I found a few possible quirks:
You set GIE inside the timer ISR. This allows other interrupts to interrupt your CCR0 ISR. However, it also allows Tiemr0 interrupt to interrupt itself. I don't think the code in onTimerInterrupted is re-entrant and will correctly run if this happens. So depending on the configured delay, you might get erratic behavior.It's better to set a flag in the timer and in main, just wait for the flag being set and then run the onTIemrInterrupted function. Especially if it takes longer. In this case, you might miss a timer interrupt if execution takes too long, but you don't get messed-up by the code being interrupted by itself.
It's not necessary to clear CCIFG bit in TA0CCTL0. This is automatically done on ISR entry by hardware. This is an exception that applies only to CCR0 register interrupts and the ADC10 interrupt. All other ISRs must clear their IFG bits either manually or by reading their IV register (or serving the reason by e.g. writing to TXBUF).This is because CCR0 has only exactly one possible interrupt source. So it is safe for the hardware to assume that with entering the ISR the interrupt has been handled.
A possible explanation for your original problem could be one of the most common but also most difficult to track reasons: a stack overflow.
By enabling GIE, you use nested interrupts, which may significantly increase the space required for the stack. It's possible that the stack grows into your global variables, which completely screws your program logic and may make your program do things you'd never expect. Also, writing to these global variables while the stack has flown over them causes the stack to be altered, and with it the return addresses to return to from interrupt. So it may be that you return from an interrupt to a piece of code that wasn't executing when the interrupt fired, continuing your program at a totally different point or with suddenly changed processor registers.Usually, this will sooner or later lead to a device reset. But that's not necessarily the case, depending on the application. The larger the application (and therefore the memory area with valid code), the more likely it is that the code just continues at a random point without reset - and with a puzzled developer.
Jens-Michael GrossSorry for the long delay.I hope you figured out what's going on in the meantime.
Well, I've worked "around" the problem by integrating the onTimerInterrupted() function into the user task timer interrupt, which I've set to an approximately 1ms...
Jens-Michael GrossIt's not necessary to clear CCIFG bit in TA0CCTL0. This is automatically done on ISR entry by hardware. This is an exception that applies only to CCR0 register interrupts and the ADC10 interrupt. All other ISRs must clear their IFG bits either manually or by reading their IV register (or serving the reason by e.g. writing to TXBUF).This is because CCR0 has only exactly one possible interrupt source. So it is safe for the hardware to assume that with entering the ISR the interrupt has been handled. A possible explanation for your original problem could be one of the most common but also most difficult to track reasons: a stack overflow.
So not clearing the flag, enabled the GIE, and used a CCRx where x!=0 would caused a stack over flow?(I didn't commit that implementation since it did not work, so I don't remember clearly if that was the implementation, but it could have been this)
Jens-Michael Gross So it may be that you return from an interrupt to a piece of code that wasn't executing when the interrupt fired, continuing your program at a totally different point or with suddenly changed processor registers.Usually, this will sooner or later lead to a device reset. But that's not necessarily the case, depending on the application. The larger the application (and therefore the memory area with valid code), the more likely it is that the code just continues at a random point without reset - and with a puzzled developer.
This is scary stuff... I've experienced this in debug, the application running paused every time in a weird assembly line, and I was puzzled how it got there...(I've just realized what I did wrong and fixed it)
It is really weird I'm writing about this today, because today I think (99% positive, but I can always be wrong) I've experienced this sort of behavior with Java at work.This is really messed up because I know Java to its core (The Java core not the C layer under it), and was shocked today, as and for the first time in my carrier, executing a 100% valid flow of code through the execution, to the nearest catch, with a consistent impotent NullPointerException (There were no NULLs there I'm sure of it, there were 4 eyes on the code), and after hundreds of executions, where the execution failed at random lines, I've left work puzzled... again.
Thinking about it now, killing a Java thread while executing its binaries, actually might cause this sort of behavior... will check if this is the case first thing Sunday :)
Thank you really much for all the help.
Adam ZehaviSo not clearing the flag, enabled the GIE, and used a CCRx where x!=0 would caused a stack over flow?(I didn't commit that implementation since it did not work, so I don't remember clearly if that was the implementation, but it could have been this)
When an ISR is entered, GIE is implicitely cleared. When teh IF Tbti that cause teh interrupt is still set when GIE is set again (by leaving the ISR and restoring the previous state of the status register, which had GIE set, or by manually setting GIE inside the ISR) the same ISR will be called immediately (or, if there is a higher-priority interrupt pending now, this one will be handled first)
So if you don't clear the IFG bit before GIE is set again (either manually, or by reading the associated IV register or e.g. by reading RXBUF / writing to TXBUF), the ISR will go into an endless loop of ISR calls and MAIN will stop executing. If you set GIE inside the ISR, this will cause teh ISR to be called whiel it is already executing, piling up a return address on the stack on each loop.
Only for CCR0 and ADC10 interrupt, the hardware auto-clears the IFG bit. Unless you have another interrupt happening while you're still in your ISR, you won't ever see these two IFG bits set inside their ISR.
Adam Zehavitoday I think I've experienced this sort of behavior with Java at work.
I'm fairly new to Java (our metering data server is java-based and I just started to dig into the huge codebase - before (and still), I worked on the flex-based client application for 2 years now. But what I learned from my colleague (when he was talking about his problems with the code he inherited from some outside coders) was that java is quite stable regarding this kind of things. However, with increasing complexity of system, chances increase that bugs survive long periods undetected.
Jens-Michael Gross When an ISR is entered, GIE is implicitely cleared. When teh IF Tbti that cause teh interrupt is still set when GIE is set again (by leaving the ISR and restoring the previous state of the status register, which had GIE set, or by manually setting GIE inside the ISR) the same ISR will be called immediately (or, if there is a higher-priority interrupt pending now, this one will be handled first) So if you don't clear the IFG bit before GIE is set again (either manually, or by reading the associated IV register or e.g. by reading RXBUF / writing to TXBUF), the ISR will go into an endless loop of ISR calls and MAIN will stop executing. If you set GIE inside the ISR, this will cause teh ISR to be called whiel it is already executing, piling up a return address on the stack on each loop. Only for CCR0 and ADC10 interrupt, the hardware auto-clears the IFG bit. Unless you have another interrupt happening while you're still in your ISR, you won't ever see these two IFG bits set inside their ISR.
I see...
Jens-Michael Gross Adam Zehavitoday I think I've experienced this sort of behavior with Java at work.In Java, you don't deal with the stack, and also, teh stack usually has its own memory segment. SO if the stack overflows, you should get a java stack overflow exception explicitely stating that the stack has exceeded the assigned stack size. SInce a typical Java processor has a memory management unit that detects memory access beyond the reserved and granted size, and since global data don't share the same memory segment with the stack, it's very unlikely to get the stack corrupted by data writes and v.v.
Actually, I was not referring to that behavior you mentioned, but more to the uncharted memory location, which would assumably cause a NullPointerException, without any stack trace, also in Java you have access to the Thread stack information, but the integrity of the stack would be destroyed together with the killing of the thread. (at least in theory)
Adam Zehavimore to the uncharted memory location, which would assumably cause a NullPointerException, without any stack trace, also in Java you have access to the Thread stack information, but the integrity of the stack would be destroyed together with the killing of the thread. (at least in theory)
mythread.object.target = targeta = mythread.objectmythread.object.target=null;
then a.target will suddenly be a null pointer too, even though mythread.object won't be discarded as long as a contains its reference.
I was actually wrong, one of the objects deep in the hierarchy was null, due to race condition, and an idiotic implementation of the project, what's weird is the fact that there was no stack trace, and that while debugging, the debug stepping resulted in a jump to a synchronized block declaration, and only then landing impotent in the catch block, this never happened to me before... I still not sure why it behaved that way...