This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: Spurious timer interrupt

Part Number: TM4C123GH6PM

I am getting a spurious timer interrupt.

I am calling it "spurious" because I believe it should not occur until after the timer runs through its count period and times out. But it happens immediately.

It is more-or-less repeatable, occurring about 50% of the times that I attempt to reproduce it. It occurs during the startup logic of the program, just after I enable the interrupt, especially after flash programming the part via CCS to launch a debug session, but can occur after System Reset or Core Reset as well.

I believe this happens because GPTMRIS / GPTMMIS bit 0 is already on, possibly from a previous run through the program, or possibly because of my mistake. I have not yet traced the cause of this bit being 1.

The strange thing is, I believe that my timer setup code should be clearing this. I am using TivaWare calls only.

I was under the impression that calling TimerIntClear() before performing the sequence TimerIntEnable(), IntEnable(), TimerEnable(), should result in the interrupt NOT being triggered until AFTER the timer has timed out.

But apparently TimerIntClear() is not enough. What additional calls must I make prior to TimerIntEnable(), IntEnable(), TimerEnable() to avoid this problem?

  • Hi,
    Which interrupt vector number does the CPU jump to? I just want to make sure it is one of the timer module ISR the CPU jumps to.
    Can you please confirm if GPTMRIS/GPTMMIS bit 0 is indeed set? If you believe the interrupt comes from the timer before the timer is even enabled, perhaps you can temporarily modify the timer ISR and put a while(1) and investigate the NVIC and also the timer registers.
    If you have a different board can you repeat the same behavior? This will help isolate the problem to your program code.
  • Thank you for your reply. I will place the while(1) loop and look into NVIC. Which registers are the most likely culprits, if you guess based on experience?
  • Hi twelve12pm,
    I think you want to start with the PRIMASK, ENx and PENDx registers to see if they are set during the startup since you reported that interrupt was taken before even running to main where your code will enable the interrupts.

    I will also suggest that you take a look and run the timers.c example from TivaWare library. The example generates periodic interrupt. It will not generate interrupt until the interrupt is enabled.
  • Incidentally when looking at registers, how do I know when to use the Vector Number (37 in this case for INT_TIMER1A) and when to use the Interrupt Number (21 in this case)? Just to clarify, INT_TIMER1A will show up in NVIC Register EN0 Bit 21, not in EN1 Bit 5?

    Also, in Table 2-9 page 104 of the TM4C123GH6PM datasheet, what is the meaning of the Vector Address Or Offset column? -- for this vector / interrupt it gives 0x0000.0094. What does this number refer to? Thanks for your patience :-)
  • Previously I was mistaken. The interrupt does not trigger before main() runs. It triggers immediately after the timer and interrupt are enabled, but before the timer has run through its period. I think I know why, but not 100% sure yet. Here's what I found so far:

    1. My timers are configured to continue running when the core is paused. (That is a mistake and needs to change.)

    2. When the program ran previously, the timer and interrupts were enabled.

    3. Because of (1) and (2), when CCS flash-programs the part and starts a debug session, the timer (which triggers every 1 ms) continues to run, times out, and sets GPTMRIS / GPTMMIS bit 0.

    4. NVIC pends the interrupt (NVIC_NVIC_PEND0 0xe000e200 bit 21 is set)

    5. When the core starts executing again, these bits are still set, both in timer peripheral and in NVIC. (It appears CCS performs a Core Reset, not a full System Reset. The difference is that a Core Reset leaves these registers intact; a System Reset clears them. Of course, the program must be made to work correctly no matter how reset occurs.)

    6. My init code, in a valiant but failed effort to prevent this situation, was calling SysCtlPeripheralDisable(), SysCtlPeripheralReset(), SysCtlPeripheralEnable(). This clears GPTMRIS / GPTMMIS but the damage (NVIC_NVIC_PEND0) is already done.

    7. Similarly, TimerIntClear() clears GPTMRIS / GPTMMIS but does not unpend the interrupt in NVIC

    8. Later in the program, the timer and interrupts are enabled; immediately, the interrupt, which has been pending all this time, triggers.

    If this is correct, then I need to unpend the interrupt in my startup code, before enabling the interrupt. I think I should go even further and unpend all interrupts, to make sure this situation does not arise again. And once I verify that this solves the issue, I need to configure timers to pause on CPU halt.
  • Hi twelve12pm,
    You have a sound analysis of the problem. Even for a CPU core reset, the NVIC registers are supposed to be cleared. What might have happened is that you have the IntMasterEnable() probably early in your main code before you call TimerIntClear(). During this window, there could be an timer interrupt generated from the previous run.
  • Hi Charles,

    The NVIC is part of the ARM core so it makes sense that those registers should be cleared. However from what I'm observing, it appears they are not. I am using the CCS Memory Browser. Is that considered the correct way to examine such registers?

    IntMasterEnable() is playing a role. The program is structured as a polled superloop. Each module in the program (there are quite a few!) is structured as a finite state machine. Some of these, like the module that uses the timer in question, can be started, stopped, and restarted. This was working almost correctly, except for the unwanted interrupt of course!

    The structure of main is very standard:

    1. Initialize hardware

    2. Call IntMasterEnable()

    3. Run the superloop

    Somewhere in step 1, the timer peripheral is being partly initialized with the sequence of calls: TimerConfigure(), TimerUpdateMode(), TimerPrescaleSet(), TimerLoadSet(), IntPrioritySet(), TimerIntClear().

    Later in step 3, when the superloop is running, an event occurs which shall enable the timer and interrupt. At that time, I am entering a critical section with IntMasterDisable(), then executing this sequence of calls: TimerLoadSet(), TimerIntClear(), TimerIntEnable(), IntEnable(), TimerEnable(), then exiting the critical section with IntMasterEnable().

    The unwanted interrupt is triggered immediately after this IntMasterEnable().

    Where in TivaWare should I search for a function to unpend the interrupt? I will add that to the timer-enabling sequence.
  • Nevermind, I found it: IntPendClear(). How obvious is that?! I'll test and report back if this solves the issue. Thanks for all your help.
  • In tests, it appears that adding IntPendClear() call just prior to enabling the timer and interrupt prevents the unwanted interrupt. The lesson here is that interrupt management is split between the peripheral and the NVIC, and both must be managed to achieve the desired outcome.

    Incidentally I am glad you recommended the timers.c example because I learned something unrelated but VERY important: FPULazyStackingEnable()!! I was under the impression that the compiler stacks the floating point registers if used, but apparently that is not the case and stacking must be enabled explicitly with either this call or the more drastic FPUStackingEnable(). Lack of this call could have created problems VERY difficult to trace!

    As an aside, since we were speaking of Core Reset, I have an interesting unrelated problem with TM4C129 where new debug sessions often launch the chip into some la-la land, with the program counter set to some strange 0xfffffffe value until I manually pause, perform a System Reset, and restart. This only occurs with debugging, only with GCC, and I have not seen it happen on normal power-up. I suspect strongly that it is something wrong with my startup file and/or customized linker script. I'm mentioning it here only because we were speaking of Core Reset and whether things are cleared or not. I'll pursue that in a separate thread at a later time...
  • twelve12pm said:
    I was under the impression that the compiler stacks the floating point registers if used, but apparently that is not the case and stacking must be enabled explicitly

    Just a note as a matter of perspective. This is true on most micros and for good reason. Having to save the floating point register set in some fashion adds considerable latency to an interrupt, for some RTOS/micro combinations this is optional even for task switches because of the overhead involved. Always, always be suspicious of floating point behaviour in the presence of task switches and interrupts until you have verified the details.

    Robert

  • twelve12pm said:
    The lesson here is that interrupt management is split between the peripheral and the NVIC, and both must be managed to achieve the desired outcome.

    Before "drinking the Kool-Aid" - or raising theory to lesson status - might the following be considered:

    • No/Zero vendor timer examples - both w/in the Peripheral Folder & elsewhere - employ such "split" mgmt. effort/concern
    • Firm/I - having employed predecessor vendor (LMI) and current vendor's incarnations (10+ years) - also have found, "No such "split" mgmt. need.
    • If this "lesson" proved true - would not (many) have flagged this - sought help?    (apparently they have not)
    • "Lesson status" - from one board, one IDE, one user, possibly a highly individualized set-up/config - may prove an "over-promotion."

    No one discounts your time/thought/effort - yet such "generalization" demands a more rigorous examination - and the considerations (listed above) require (some) attention...

  • Robert Adsett72 said:
    twelve12pm
    I was under the impression that the compiler stacks the floating point registers if used, but apparently that is not the case and stacking must be enabled explicitly

    Thanks for your input. I am glad I learned this the easy way and not the hard way! Will be more careful with floats from now on. :-)

  • cb1_mobile said:
    twelve12pm
    The lesson here is that interrupt management is split between the peripheral and the NVIC, and both must be managed to achieve the desired outcome.
    • No/Zero vendor timer examples - both w/in the Peripheral Folder & elsewhere - employ such "split" mgmt. effort/concern
    • Firm/I - having employed predecessor vendor (LMI) and current vendor's incarnations (10+ years) - also have found, "No such "split" mgmt. need.
    • If this "lesson" proved true - would not (many) have flagged this - sought help?    (apparently they have not)
    • "Lesson status" - from one board, one IDE, one user, possibly a highly individualized set-up/config - may prove an "over-promotion."

    No one discounts your time/thought/effort - yet such "generalization" demands a more rigorous examination - and the considerations (listed above) require (some) attention...

    Dear cb1_mobile,

    Your input is always appreciated. I agree with you on most points here, certainly that the "lesson" learned here is probably tied to our specific combination of hardware, software, developer tools, our weird customized linker script and startup files, launch configuration, desktop OS, and who knows what else.

    I am not discounting what you said about you and your firm using these parts for over ten years without running into this issue. There are most likely differences in how we're working with these chips, a situation not helped by our being very new to TM4C and ARM.

    Nevertheless, I saw clearly that the NVIC PEND registers contained a 1 when they shouldn't have, or more accurately when I didn't want them to. When CCS is going through the sequence of flash programming the part and starting a Debug session, it appears that the part is reset several times and, as CCS moves from one step to the next, the part is released from reset and runs through the program partially before being reset again. It appears to be Core Resets, which despite what I've read appear not to reset certain things. This is probably an artifact of something in our particular setup.

    Whatever the reason, it doesn't matter. The program must initialize the chip and work correctly, even if the problem (currently) manifests only during flash programming and debug -- consider, for example, what happens if we implement a bootloader and perform flash upgrades in the field. We cannot allow stale state from a previous run to affect execution. This is no different than entering a C function and initializing its local variables, because you cannot and must not assume that they are clear on entry. They may be, sometimes, but there is most likely old data in that memory.

    Also, I don't think it's too much of a stretch to say that interrupt handling is split between peripheral and NVIC. Consider for example that you must do TimerIntEnable() AND IntEnable() to enable an interrupt. So, since as we've seen, it is possible for previously pended interrupts to remain pended, waiting until the moment you enable them, I think it's sensible, during initialization, to handle this possibility by unpending the interrupt. Even if it accomplishes nothing, you don't lose anything by doing it.

  • Thank you - again you raised an interesting point - and if you return to a past post of yours (which I was able to resolve) - "pending of interrupts" WAS well noted!       (found at/around the back end of your thread)

    As you are a "bit" of a "detail maven" - it is wondered how much of such issue arises due to your choice of IDE.       Can that here (realistically) compete against a far more mature, far more accommodating (i.e. "any" ARM vendor's MCU), vastly larger (and satisfied) user base - and (singularly) focused upon the "IDE?"      (thus the size & resources available for, "Exclusive IDE Development & Support" are likely to "dwarf" those of any single, broad-based (primarily chip) vendor - are they not?)

    Devoting your significant: Tech Skill, Time, Effort - to that which may prove a, "single vendor anomaly" (weakness) - may prove sub-optimal.     In addition - how can your "locking yourself in" to one vendor be justified?      Where ARE the M0's, M3s, M7s (all Cortex) - you must be aware that vendors - almost regularly - "leapfrog one another" - thus "single vendor MCU & IDE devotion" appears "out of sync" w/your usual "well thought, presented & directed efforts" - regularly arriving here...

    As one (potential) comparison effort - IAR provides a 32KB (code size limited) FREE version of their ARM "Kickstarter."      The fact that thousands have (willingly) PAID for the "normal" versions - enabling the free & eased migration to (other) ARM MCUs - points to the power, efficiency, and (multiple) advantages that such "IDE Specialization/Exclusive Focus " surely creates...

  • cb1_mobile said:

    Thank you - again you raised an interesting point - and if you return to a past post of yours (which I was able to resolve) - "pending of interrupts" WAS well noted!       (found at/around the back end of your thread)

    As you are a "bit" of a "detail maven" - it is wondered how much of such issue arises due to your choice of IDE.       Can that here (realistically) compete against a far more mature, far more accommodating (i.e. "any" ARM vendor's MCU), vastly larger (and satisfied) user base - and (singularly) focused upon the "IDE?"      (thus the size & resources available for, "Exclusive IDE Development & Support" are likely to "dwarf" those of any single, broad-based (primarily chip) vendor - are they not?)

    Devoting your significant: Tech Skill, Time, Effort - to that which may prove a, "single vendor anomaly" (weakness) - may prove sub-optimal.     In addition - how can your "locking yourself in" to one vendor be justified?      Where ARE the M0's, M3s, M7s (all Cortex) - you must be aware that vendors - almost regularly - "leapfrog one another" - thus "single vendor MCU & IDE devotion" appears "out of sync" w/your usual "well thought, presented & directed efforts" - regularly arriving here...

    As one (potential) comparison effort - IAR provides a 32KB (code size limited) FREE version of their ARM "Kickstarter."      The fact that thousands have (willingly) PAID for the "normal" versions - enabling the free & eased migration to (other) ARM MCUs - points to the power, efficiency, and (multiple) advantages that such "IDE Specialization/Exclusive Focus " surely creates...

    As far as my choice of IDE, currently we are using CCSv7 for TM4C programming.

    Thanks for mentioning the IAR Kickstarter.

    Generally speaking, I don't really care what the IDE is, as most time is spent editing code and I never use the IDE for that. I do all source code editing in a paid text editor that we've been using for almost two decades now, UltraEdit.

    The reason is that in addition to embedded programming on a handful of MCU platforms, we maintain desktop software on three platforms, so as far as IDEs go, I personally use various incarnations each of MS Visual Studio, Eclipse (including CCS), Xcode, Code::Blocks, and a variety of smaller older IDEs, sometimes (yes) in the same day! Each has its own slightly different keystroke combinations for similar operations, some can do things others can't, and "Clean" in Eclipse is called "Rebuild All" in MS Visual Studio. It's enough to make one's head spin! So regardless of IDE or platform, the IDE's purpose is limited to building, flash programming, and debugging.

    It would be nice, though, if I could ever figure out what the Debug properties (in Project Properties) do, and how the settings we have affect our flash programming / debugging.

  • The simple fact that the (lesser) IDE (alone) may have caused your delay & frustration - has been avoided. "Avoidance" is never held in high favor - seems (much) away from your "norm." (as detected here - till your most recent writing.)

    Tools ARE of critical importance - compromising "there" proves seldom a, "wise and/or productive" choice...
  • I can tell you're not a fan of CCS. I can tell you that I've seen worse... Much worse. I've also seen better, which is to say, I prefer small, simple, easy-to-use IDEs, and those whose project file format lends itself to being placed under version control. CCS is based on Eclipse, so it's huge and comes with all the advantages and disadvantages thereof. I'm not saying that's necessarily a good thing or a bad thing, simply that it is what it is. Fortunately (or unfortunately, depending on your point of view) I've used Eclipse since circa 2007 so I know how to deal with it.

    Tools are crucial. I agree wholeheartedly.

    BUT... What I try to avoid is switching horses mid-stream. It's very easy to choose a set of tools, languages, etc., start a project, run into a problem (problems are inevitable no matter the tools), and start switching horses. I've worked with enough large software package to know that ALL tools come with caveats. Sure, we could switch, but we're using this one BECAUSE WE DID SWITCH! So my philosophy is, we got the tools to work, the program loads into the chip, and single-stepping in the debugger works correctly. There will be the inevitable problems and we'll just have to work around them, mitigate them, or deal with them somehow. When we start the next project, we can evaluate other possibilities.

    As far as the IDE causing the issue that prompted this thread, that is possible but hasn't been proven. What has been demonstrated to my satisfaction is that my code was not doing enough to ensure it was initializing to a sufficiently clean state, whatever the state of the core or chip when the program starts. I consider this far more important than pointing fingers at the IDE or other tools. As far as I'm concerned, I don't care what the development system looks like. I only care that the product turns on and functions correctly regardless if that's from cold power-on, a warm reboot, a firmware upgrade, or whatever situation. (And that single-stepping works. That's my biggest pet peeve, when single-stepping doesn't work. Yes I know that you're supposed to compile with -O0 and debug information. I'm talking about certain IDEs where it STILL doesn't work half the time!)
  • twelve12pm said:
    I can tell you're not a fan of CCS. I can tell you that I've seen worse... Much worse. I've also seen better, which is to say, I prefer small, simple, easy-to-use IDEs, and those whose project file format lends itself to being placed under version control. CCS is based on Eclipse, so it's huge and comes with all the advantages and disadvantages thereof.

    *LIKE* *LIKE* *LIKE* *LIKE*

    I'm completely in agreement with you.

    The good news is the only thing you need an IDE for is if you use it for an interactive debugger (I may depart from most here in seldom having use for such). Otherwise any decent compiler can be run from a build system such as make and then you can use the editor and other tools you are familiar and productive with.

    Unless constrained in some other fashion, I always first get the tools running from the command line. It's usually straightforward and leaves you in full control.

    Robert

    The only time I've found an IDE required was for a C compiler whose resemblance to C was mostly coincidental.

  • Robert Adsett72 said:
    twelve12pm
    I can tell you're not a fan of CCS. I can tell you that I've seen worse... Much worse. I've also seen better, which is to say, I prefer small, simple, easy-to-use IDEs, and those whose project file format lends itself to being placed under version control. CCS is based on Eclipse, so it's huge and comes with all the advantages and disadvantages thereof.

    I'm completely in agreement with you.

    The good news is the only thing you need an IDE for is if you use it for an interactive debugger (I may depart from most here in seldom having use for such). Otherwise any decent compiler can be run from a build system such as make and then you can use the editor and other tools you are familiar and productive with.

    Unless constrained in some other fashion, I always first get the tools running from the command line. It's usually straightforward and leaves you in full control.

    Robert

    The only time I've found an IDE required was for a C compiler whose resemblance to C was mostly coincidental.

    We may have to adopt a command line build system. As far as I know, it's practically mandatory if you use CI (Continuous Integration). Currently we manually go through a procedure of building  various build configurations, running automated tests on multiple platforms, etc. CI could automate that, but will obviously take some effort to get up and running.
    Speaking of automated tests and the debugger... In our applications, it is often not feasible to use a debugger because the program cannot be stopped. So we minimize the need for a debugger two ways: We instrument our code, making it possible to display "live" data on a computer, and we have an automated test suite for all platform independent (algorithmic) code. We build those tests with a variety of compilers and run them on several platforms. When all tests pass on all compilers and all platforms, that does not guarantee that it's correct, but it provides a certain level of confidence. We've caught many obscure bugs over the years with automated tests. Between these two things, we only have to resort to the debugger in case of low level platform-specific things, like the one that prompted this thread.
  • twelve12pm said:
    We may have to adopt a command line build system. As far as I know, it's practically mandatory if you use CI (Continuous Integration).

    Either that you you have to script the GUI, I think.

    twelve12pm said:
    Currently we manually go through a procedure of building  various build configurations, running automated tests on multiple platforms, etc. CI could automate that, but will obviously take some effort to get up and running.

    My current build process.

    • make. I keep looking at other systems but so far none appears to be 'better'. I have a system that results in small makefiles to manage the build process but it does need support files built up.
    • PC-Lint. Other static analysis tools could be used but PC-Lint is very effective (with strong typing and value tracking) and not expensive.
    • Unit test (Currently Google test and FFF)
    • compiler as appropriate

    Make enforces a lint, test, compile order. No code is tested until it passes lint. No code is compiled until it passes unit tests and the build will fail if unit tests are missing. Any auto generated code is done before linting. There are project and system level make configuration files that deal with setting up rules and selecting appropriate compilers and options.

    Lint is also used as a dependency generator (along with some sed and awk scripting) . One of make's weaknesses is keeping track of header files. This deals with that nicely. Lint also has system (these are the default rules) and project (These are the exceptions for this project. Vendor libraries etc...) configuration files.

    In the mental queue to add.

    • Linting the test cases
    • Adding hardware unit tests.

    If you are not using PC-Lint or the equivalent, I cannot recommend it highly enough. It will detect errors that elude other testing, particularly type errors. Surprisingly, it will find error that are basically design errors. Not directly, but simply as a consequence of the errors it does find. If used consistently it will change the code you write for the better, especially as you turn up the heat. #PC-Lint range and value checks

    twelve12pm said:
    Between these two things, we only have to resort to the debugger in case of low level platform-specific things, like the one that prompted this thread.

    I wouldn't use a debugger for this either. Generally I only unearth it for hard race conditions and the like (just how did we get to this impossible point?).

    Robert

  • We been using PC-Lint since 2006, but not the way you're using it. It generates a ton of output, much of which is not applicable to us. Yes, I know it can be instructed to suppress certain messages, and probably we'll have to do that. I was thinking of coming up with several configurations, one of which would show only the most important messages and run automatically, and others which would have varying levels of verbosity, to be run manually from time to time.

    For now, we use it the manual way with lots of verbosity and we painstakingly sift through the output, looking for anything egregious. It is a valuable tool and it has caught some tricky stuff in the past.

    One of the biggest things we have done to make our code more reliable is to structure much of it into self-contained libraries, which we pull into our working copy using svn:externals. This code gets compiled together with the rest of a firmware project. This eliminated a huge problem we had in the past, where many frequently used functions were copied and pasted from one firmware project to another, and inevitably ended up with slight code changes between them. Some bugs were fixed in one firmware but not another. It was a nightmare. At one point, we took the time to collect all of these functions, reconcile all of them, and structure them into our library, which is managed as its own Subversion project with its own version numbering, etc., just like a library from an external vendor would be. It is heavily tested in a test suite we wrote, which we compile with MSVC, GCC, LLVM, TI's compiler, and several others, with varying versions of the C standard, and run on multiple hardware platforms. All tests pass. We know it's good and it works. We also get the advantage that if the library is extended in some way, our firmware projects don't break because svn:externals pulls a very specific tagged "release" of the library, until we explicitly tell it to use a newer release. So we can hack on the library at will without fear of breaking anything, then create a "release" once it's tested, and update each firmware project to a newer release only when ready to do so.
  • twelve12pm said:
    We been using PC-Lint since 2006, but not the way you're using it. It generates a ton of output, much of which is not applicable to us. Yes, I know it can be instructed to suppress certain messages, and probably we'll have to do that. I was thinking of coming up with several configurations, one of which would show only the most important messages and run automatically, and others which would have varying levels of verbosity, to be run manually from time to time.

    I've generally found that most of the 'not applicable to us' messages are either misconfigurations or they really are applicable and you haven't recognized it yet, at least at the lower warning levels. I do have to turn off a reasonable number but then I also run at -w4.

    Lint catches a lot of things and its messages are a lot better than any compiler I've used. It also catches at least some items like bad argument values (I've seen no compiler that can manage that) and it does so much earlier in the process than testing.

    twelve12pm said:
    For now, we use it the manual way with lots of verbosity and we painstakingly sift through the output, looking for anything egregious.

    This practically guarantees that you won't use it regularly and you certainly won't get the full benefit.

    This is my std.lnt which included in all projects regardless of processor

    // Standard (non-processor specific lint options
    // Included by processor specific file 
    au-misra2.lnt
    -esym(960,16.9)	// In direct contradiction to error 540, chose 540 no & in front 
    		// of function when referenced as pointer
    -elib(960)	// Libaries likely not MISRA compliant
    
    -A		// ANSI compliance
    +stack		// Track stack usage
    -estring(974,*recursive*)   /* worst case function stack usage Turn off MISRA Complaint*/
    -passes(6,-v)	// 6 passes, report on calls and walks
    -w4		// Turn up warning level
    -rw(*ms)	// No ms keywords
    -strong(AizXJcmdz)// Ignore strong type on init
    		// Allow comparison to and assignment of 0
    		// Dimension everything
    		// Ignore combining with constants
    		// Ignore multiplication operators (rely on dimension checks)
    -strong(B,bool)	// Boolean		
    	// Basic types are not strong 
    -strong(,uint32_t)
    -strong(,int32_t)
    -strong(,uint16_t)
    -strong(,uint8_t)
    -strong(,uint_least8_t)
    -strong(,uint_fast8_t)
    -strong(,int16_t)
    -strong(,int_fast8_t)
    
    -ffn		// Reports full filename
    +fod		// Export all declared objects to lobs (helps with linting via make)
    +fsc		// Strings are const
    +fxa		// pointer/array matching in args
    -vfs#h-		// What to present as lint executes
    -vh
    -hsFa|3		// Message presentation
    -format=%("%f",%l\s\s%)%t\s%n:\s\s%m 
    
    -e537		// Too noisy.  Effectively dissallows nested includes.
    // Turn on optional messages.  Messages marked experimental are being trialed 
    +e909		// Implicit conversion to bool
    -e910		// Allow 0 to be equivalent of NULL
    -e911		// Promotion of shorter integer types to larger implicitly
    -e912		// Implicit conversion to a larger type in an operation
    -estring(915,assignment) // Implicit conversion on assignment 
    +e916		// Implicit pointer assignment
    -e920		// Cast to void.  Throws up complaints about using void to 
    		//  ignore return values.
    -e921		// Allow explicit integral type to integral type cast.		
    -e925		// MISRA C++ pointer to pointer cast 
    -e935		// int used as type for structure member
    +e936		// K&R style function definition
    +e937		// K&R style function declaration
    +e938		// Parameter not explicitly declared
    +e940		// Return type defaults to int
    +e941		// Operation evaluates to 0
    +e942		// Possible truncated addition
    +e944		// Argument to boolean operator evaluates to fixed value
    +e945		// Undefined struct used with extern (portability)
    +e950		// non-ISO/ANSI reserved word
    -e952		// Parameter could be declared const (but C is pass by value)
    +e953		// Variable could be declared const
    +e954		// Pointer variable could be declared const
    +e955		// Parameter name missing from prototype
    +e956		// Experimental - Non-const, non-volatile external (thread check)
    +e957		// Function defined w/o prototype
    -e958		// Padding required.
    -e959		// Struct size not a multiple of alignment
    +e960		// MISRA required
    +e961		// MISRA Advisory
    -esym(961,19.7)	// Allow function-like macros
    +e962		// Symbol redefined identically
    -e964		// Header file not used directly but includes file taht is.
    -e970		// MISRA don't use bare types? 6.3
    -e971		// Use of char w/o signed/unsigned Traps use as string pointer
    -e974		// Worst case stack usage always fails lint
    -e1960		// MISRA C++ error (We don't have any C++)
    -esym(829,string.h)	// Allow use of memory functions
    -esym(829,limits.h)	// Allow use of size defines (MISRA C++ forbids)
    -esym(829,stddef.h)	// Allow use standard defines (MISRA C++ forbids)
    -header(c:/lint/unit_check.h)
    

    As you can see it's fairly short. It doesn't turn off much and in fact turns on additional warnings.

    And my project.lnt It sets options specific to Tivaware and tm4c and other concerns specific to the project/processor

    // TivaWare specific options. 
    +libdir("C:/Tiva")
    --elibmacro((923))	// int to pointer cast
    -elib(960)		// No MISRA compliance expected
    --elibmacro((960))	// No MISRA compliance expected
    --elibmacro({960})	// No MISRA compliance expected
    --emacro((917),*_BASE)	// Base offset macros declared as signed, should be unsigned.
    --emacro((835),ADC_CTL_*)// Some CTL macros are zero (and then orred to produce control).
    --emacro((912),CAN_INT_*)// CAN_INT macros declared as signed, should be unsigned.
    --emacro((912),GPIO_*)	// GPIO macros declared as signed, should be unsigned.
    --emacro((915),GPIO_*)	// GPIO macros declared as signed, should be unsigned.
    --emacro((917),GPIO_*)	// GPIO macros declared as signed, should be unsigned.
    --emacro((917),INT_*)	// INT macros declared as signed, should be unsigned.
    --emacro((912),MSG_OBJ_*)// MSG_OBJ macros declared as signed, should be unsigned.
    --emacro((915),MSG_OBJ_*)// MSG_OBJ macros declared as signed, should be unsigned.
    --emacro((912),NVIC_*)	// NVIC macros declared as signed, should be unsigned.
    --emacro((835),SYSCTL_*)// Raised when 0 values macros are orred.
    --emacro((912),SYSCTL_*)// SYSCTL macros declared as signed, should be unsigned.
    --emacro((915),SYSCTL_*)// SYSCTL macros declared as signed, should be unsigned.
    --emacro((917),SYSCTL_*)// SYSCTL macros declared as signed, should be unsigned.
    -esym(960,5.1)		// TIVA uses long names
    -elib(950)		// TIVA non-ANSI constructs notably single line comments
    -elib(659)		// Nothing follows } on line terminating struct/union/enum definition.
    -"esym(793,macros in module)"		// ANSI/ISO limit of 1024 macros in a module exceeded by TIVA headers
    -"esym(793,significant characters in an external identifier)" //ANSI identifier length limit of 6 for external identifiers 
    -e966 			// indirectly included header not used
    -doffsetof(x,y)=((size_t)0)	// IAR's offsetof does not lint well at all
    -e586				// offsetof used in setting up data structures.
    
    	// New lint errors look to provide standard response
    -elib(9026)	// Function like macro
    -elib(9022)	// Unparenthezised macro parameter
    -elib(9021)	// Use of #undef discouraged
    -elib(9024)	// #/## used in macro
    -elib(9023)	// Multiple use of #/## used in macro
    -elib(9050)	// Dependence on operator precedence
    -elib(9020)	// Header file with non-standard character \
    -elib(9057)	// Lowercase L follws u in suffix
    -elib(9059)	// C comment contains c++ comment
    -elib(9048)	// Unsigned literal w/o U suffix
    --emacro((9048),SYSCTL_*)// SYSCTL macros have unsigned literal w/o U suffix.
    --emacro((9048),NVIC_CPAC)// SYSCTL macros have unsigned literal w/o U suffix.
    -e9048// NVIC macros have unsigned literal w/o U suffix. Return to fix
    -e9044		// Function parameter modified
    -e9058		// tag used only in typedef (including anonymous tags)
    -e9016 		// Yes we use pointer arithmetic
    -e9017 		// Yes we use pointer arithmetic with increment/decrement
    
    	// Startup has some library-like code.
    +libm(startup.c)
    
    	// Project specific statecharts generated code
    // +fct	
    -isrc-gen	
    +libdir(src-gen)
    +libh(src-gen/coolfan.h)
    +libm(src-gen/coolfan.c)
    +libh(src-gen/canerror.h)
    +libh(src-gen/canerrorrequired.h)
    +libm(src-gen/canerror.c)
    +libm(cansupp.c)
    +libh(src-gen/xonxoff.h)
    +libh(src-gen/xonxoffrequired.h)
    +libm(src-gen/xonxoff.c)
    +libh(src-gen/SEL_parse_top.h)
    +libh(src-gen/SEL_parse_toprequired.h)
    +libm(src-gen/SEL_parse_top.c)
    +libh(src-gen/ThermalManagement.h)
    +libm(src-gen/ThermalManagement.c)
    +libh(src-gen/StringContactorRequired.h)
    +libh(src-gen/StringContactor.h)
    +libm(src-gen/StringContactor.c)
    -isrc-gen
    -elib(621)		// Long symbols produce 
    -elib(788)		// Not all enum constants used in a defaulted switch
    -elib(715)		// Not all arguments referenced
    -elib(818)		// Parameter could be declared as pointer to const
    -elib(904)		// Return before end of function
    -elib(915)		// boolean type and type of boolean constants not the same (signed/unsigned)
    -elib(506)		// Constant value boolean in logic (&&)
    -elib(944)		// Right hand argument for && always evaluates to True
    -elib(774)		// Boolean on right of && within if always true
    -elib(917)		// Prototype coercion int to unsigned int (boolean type again)
    -elib(632)		// Assignment to strong type sc_integer
    -elib(766)		// header file (string.h) not used
    -elib(9012)		// sub-statement should be compound statement
    	// Added from Yakindu 2016/03/28
    -elib(605)		// Increase in pointer capability
    -elib(9007)		// Side effects on right hand side of logical operator
    
    	// Project specific
    -e956			// Non-const, non-volatile global.  Rely on thread semantics
    -e9026			// Function like macro
    
    	// State Chart Code generator specific
    -strong(,sc_integer)	// base type, not a strong type 
    -idlen(110)		// EEEp!
    -esym(937,cANErrorIface_getTimems)	// No prototype generated if no argument	
    -esym(746,cANErrorIface_getTimems)	// No prototype generated if no argument
    -esym(628,cANErrorIface_getTimems)	// No prototype generated if no argument
    -esym(957,cANErrorIface_getTimems)	// No prototype generated if no argument
    -esym(765,cANErrorIface_getTimems)	// No prototype generated if no argument
    -esym(714,cANErrorIface_getTimems)	// No prototype generated if no argument
    -esym(937,cANErrorIface_initCAN)	// No prototype generated if no argument	
    -esym(746,cANErrorIface_initCAN)	// No prototype generated if no argument
    -esym(957,cANErrorIface_initCAN)	// No prototype generated if no argument
    -esym(628,cANErrorIface_initCAN)	// No prototype generated if no argument
    	// State Chart Code generator specific - SEL_parse_top
    -esym(43,internal)			//
    -elib(9005)	// Casting away const/volatile
    -elib(929)	// Casting away const/volatile
    -elib(740)	// Casting away const/volatile
    -elib(923)	// Casting pointer to long (converting to event id)
    -elib(946)	// relational or subtract of pointers
    -elib(416)	// Likely creation of an out of bounds pointer
    -elib(638)	// Strong type mismatch for sc_intpte_t, used for pointer range checking
    -elib(639)	// Strong type mismatch for size_t, used for pointer range checking
    -elib(737)	// Sign loss in promotion of long to unsigned long, pointer range checking.
    -elib(574)	// Signed/unsigned mix in relational, pointer range checking.
    -elib(640)	// expected bool type in bool context.
    -strong(Bl,sc_boolean)	// Boolean type in library
    //-parent(bool,sc_boolean)
    
    // Debugging here, want to remove these
    -e793			// ANSI/ISO limits enum constants to 127
    
    
    // Debugging here, want to remove these
    -e843 			// lint thinks ms_tick could be const for some reason*/
    -esym(759,ms_tick)
    -esym(765,ms_tick)
    -esym(552,ms_tick)
    -e768 			// Lint thinks task members are not referenced
    -e697	// Quasi boolean values should be compared only to zero.  Need to see what is needed to get lint to recognize bool.	 	
    	 	
    //IAR header specific
    -ident(@)
    +rw(_gobble)
    -d"@=_gobble"
    
    -d__get_SP()=0
    	// math.h has a nasty habit of redefining things
    -esym(14,__iar_Dcomp)
    -esym(14,__iar_FDcomp)
    -elib(1916)	// Some library functions have ellipsis.  Encountered in ctype.h
    -esym(762,_LocaleC_toupper*,_LocaleC_tolower*, _LocaleC_isalpha*, _LocaleC_iscntrl*)
    -esym(762, _LocaleC_islower*, _LocaleC_ispunct*, _LocaleC_isspace*, _LocaleC_isupper*)
    -esym(9004,_LocaleC_toupper*,_LocaleC_tolower*, _LocaleC_isalpha*, _LocaleC_iscntrl*)
    -esym(9004, _LocaleC_islower*, _LocaleC_ispunct*, _LocaleC_isspace*, _LocaleC_isupper*)
    -efile(451,stdlib.h) // IAR has extra bumpf so include guard is not recognized
    -sem(isdigit,pure)	// No side effects
    -sem(isalpha,pure)	// No side effects
    -esym(14,ispunct*, isupper*, isgraph*, islower*, isxdigit*,toupper*, isalnum*)
    -esym(14,isalpha*, isdigit*, isblank*, iscntrl*, isprint*, tolower*, isspace*)
    
    // Sematics to add checking for some functions
    -sem(SysCtlPeripheralReady,pure)	// No side effects
    
    // Temporarily unused
    -esym(552,RTD2_temperature) 
    
    // Options when modules combined
    -esym(769,KD_REQUEST_FLAG::KD*) //Not all bits are reference explicitly.
    -esym(769,KD_STATUS_FLAG::KD*) //Not all bits are reference explicitly.
    
    //RTA TEMP
    -e9141
    -e9117
    -e9146
    -e9126
    -e9132
    -e9130
    -e9075
    -e9078
    -e9105
    -e9083
    -e9067
    -e9148
    -e9105
    -e9131
    -e9113
    -e9133
    -e9147
    -e9080
    -e9119
    -e9114
    -e9087
    -e9079
    -e9085
    -e9115
    -e9136
    -e9138
    -e9082
    -e9077
    -e9090
    -e9125
    -e9106
    -e9139
    -e9107
    -e9122
    -e9070
    -e9127
    -e9112
    -e9129
    -e9128
    -e9091
    -e9123
    -e9092
    -e740
    -e9072
    

    This does turn off more. There's a lot of turning off error messages specifically for libraries (I'm looking at you TI) and code generators that are less than clean. And at the end is a set of recently added lint messages which need to be sorted thorough to determine their use. Not sure they turn up below w4 actually.

    In addition there is a compiler adaptation file with sizes, compiler specific defines etc... in it. Since lint semi-automates the production of this file it's easier to keep it separate.

    Robert

    PC-Lint user since about 1986 or so.

  • *** LIKE! *** (far surpasses our "PC-Lint User Guide!")      Many thanks, Robert - greatly appreciated...

  • Thank ye kindly cb1.

    BTW, anyone tempted to try this on a non-linted working project should be a little wary. The screws are turned a touch tight. This level is both workable and beneficial though if you lint continuously.

    Robert
  • Having (both) shop "Dog & Cat" we were (aware) of "Shed Continuously" - "Lint Continuously" - breaks (new) ground...