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.

MSP432E401Y: Writing an assembly language interrupt routine for the watchdog timer

Part Number: MSP432E401Y

Hi,

I'm trying to implement the watchdog timer function for my application using watchdog timer 0 with the RESEN bit set so the timer will eventually reset the processor.  My understanding from reading up on this in the slay723 technical reference manual is that the timer generates an interrupt the first time it counts down to 0, then it reloads the count and resets the processor the second time it counts down to 0.

I don't know anything about writing interrupt routines so I'm hoping someone can give me a quick tutorial on how to do this.  Right now the function is working except that during the time after the interrupt is generated and before it resets the processor it is in a tight loop in "Default_Handler()" which it says is called when the processor receives an unexpected interrupt.

Thank you,

Brad McMillan

  • Hello Brad,

    Sorry but we are not supporting assembly language applications for this device family.

    Our standard recommendation is to leverage an existing SDK example (in this case, start with nortos) and leverage that to see what direct register / assembly code is required.

    You can find a nortos example under examples\nortos\MSP_EXP432E401Y\drivers\watchdog

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

    Actually, my question doesn't have anything to do with assembly language and I shouldn't have put it in the title. 

    My question is very simple.  I've never written code to service an interrupt so I don't know how they work at all.  It seems like there must be someway to identify the interrupt associated with the watchdog timer and there must also be a way to tell the processor the location of the code you want it to execute when that interrupt is triggered. Or,

    How do I tell the processor to execute code at a particular location when it receives an interrupt from the watchdog timer?

    Thank you,

    Brad

  • Hello Brad,

    Thanks for clarifying the question, I can explain those details of course.

    For starters, the device has an interrupt vector table with addresses for the different interrupt service routines. That is how it maps a given interrupt to a portion of code to execute. There are mapping for each individual peripheral which has an interrupt in the device.

    To allow each peripheral to trigger an interrupt, there is a peripheral-specific interrupt enable that needs to be configured. There are also typically options to configure the conditions for when the interrupt should occur as well. Once that is enabled, then peripheral will send an interrupt to the NVIC when the condition for such is met.

    The NVIC is the Nested Vectored Interrupt Controller which handles prioritization of interrupts and routing them to the correct code to execute. The NVIC also needs to be told an interrupt for a given peripheral is to be expected.

    As far as the execution of the code goes, you would write a function to be an Interrupt Service Routine (ISR) which has the code you want processed at the time of the interrupt.

    Therefore, you need to associate the ISR with the interrupt vector table which I mentioned at the start of this explanation. For a non-RTOS application like this, the simplest way to do so is to add the function to the startup_msp432e401y_ccs.c file and replace the default interrupt handler in the file with function you've created to be your ISR.

    With all those steps done, when your program executes and the peripheral meets a condition for an interrupt to occur, then it will signal the NVIC of the interrupt. The NVIC will then check the interrupt vector table and direct the code execution to the ISR you have registered for that interrupt. And at that point your ISR code will run.

    Hope that explains the process in sufficient detail for you to take the next steps with your program!

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

    I'm just getting back to this and I have a couple of questions I hope you can help me with.

    I already have the watchdog timer working to the point where it resets the processor whenever it times out so I assume it is successfully sending an interrupt to the NVIC.

    I read through the section on NVIC Registers in the MSP432E Reference Manual, slau723a, and I didn't find anything in there that refers to the watchdog timer. Can you clarify how I tell the NVIC to expect an interrupt from the watchdog timer?

    I also found the Interrupt Vector Table in the startup_msp432e401y_ccs.c file. You mention that I should replace the default interrupt handler with my own Watchdog Timer Interrupt Service Routine, but I don't see anything in the vector table that refers to the watchdog timer. Can you clarify how I should replace the default interrupt handler in the file with the function I'll be creating to be the ISR?

    Thank you for your response,

    Brad

  • Hello Brad,

    I also found the Interrupt Vector Table in the startup_msp432e401y_ccs.c file. You mention that I should replace the default interrupt handler with my own Watchdog Timer Interrupt Service Routine, but I don't see anything in the vector table that refers to the watchdog timer. Can you clarify how I should replace the default interrupt handler in the file with the function I'll be creating to be the ISR?

    There is a WATCHDOG_IRQHandler entry in the startup file, so look for that.

    You can just find that entry in the interruptVectors table and replace it with your ISR function. You will need to add the function to the startup file with the extern keyword.

    I read through the section on NVIC Registers in the MSP432E Reference Manual, slau723a, and I didn't find anything in there that refers to the watchdog timer. Can you clarify how I tell the NVIC to expect an interrupt from the watchdog timer?

    Sorry I didn't mention before but the NVIC table to find the Watchdog timer is in the device datasheet, not the TRM. You can find those details in Section 6.3.3 Nested Vectored Interrupt Controller (NVIC).

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

    I found the WATCHDOG_IRQHandler entry in the startup file and I replaced it with a pointer to my own ISR function.  When I executed my program I was able to use debug to verify that the pointer was the correct value.

    To test it, I ran some code that set the watchdog timer to its maximum value and then went into a tight loop to let the timer count down to zero.  I was able to watch the timer count down using debug but at the end of the count my ISR never executed so I obviously have more work to do.

    Earlier you mentioned that "the NVIC also needs to be told an interrupt for a given peripheral is to be expected", so I assume this is the next thing I need to do to get this to work.  I read through Section 6.3.3 of the MSP432E401Y data sheet where it talks about NVIC, but it's still not clear to me how to do this.  To me it looks like I need to set bit 18 somewhere but it's not clear to me where I need to set this bit.

    Can you clarify what else I need to do to get my ISR function to execute when the watchdog timer counts down to zero?

    Thank you,

    Brad

  • Hello Brad,

    I don't know why the datasheet and TRM try and unmarry this information so much... but the datasheet provides the table but the TRM has the register details:

    2.4.1 EN0 to EN3 Registers

    Interrupt 0-31 Set Enable (EN0), offset 0x100

    Interrupt 32-63 Set Enable (EN1), offset 0x104

    Interrupt 64-95 Set Enable (EN2), offset 0x108

    Interrupt 96-113 Set Enable (EN3), offset 0x10C

    So the Watchdog would be in EN1 and you just need to enable the correct bit there to enable the interrupt in the NVIC.

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

    I set the bit in EN1 that I thought should enable the watchdog timer interrupt but it still didn't work.  As I mentioned earlier I set the timer then go into a tight loop to watch it timeout.  When the timer reaches zero I expect execution to move to the interrupt routine, but it doesn't.  It stays in the tight loop until the timer reaches zero again and then resets the MSP432.

    Here is the debug output that includes EN1:

    0xE000E100 NVIC_NVIC_EN0
    0xE000E100 20 00 08 00
    0xE000E104 NVIC_NVIC_EN1
    0xE000E104 04 05 00 00
    0xE000E108 NVIC_NVIC_EN2
    0xE000E108 00 00 00 00
    0xE000E10C NVIC_NVIC_EN3
    0xE000E10C 00 00 00 00

    As you can see, I set the 3rd bit in EN1 which I thought was the bit I should be setting to enable the watchdog timer interrupt.  The table in sect 6.3.3 says the first 16 bits are for processor exceptions and after that the watchdog timer is bit 18 (starting from zero), so it should be the 3rd bit in EN1.  I even tried setting the whole byte to FF, but it still didn't work.

    Can you see what I'm doing wrong here?

    Thank you,

    Brad

  • Hello Brad,

    I'm a little unsure about your readout because the device is little endian so I would expect the lowest byte to show 0x04.

    That said if all FF didn't work, I wonder if Master Interrupts got disabled at some point?

    Those are turned on by CPUcpsie() typically. I believe it is the PRIMASK register which is altered, so you may want to check that one.

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

    I'm pretty sure the first byte for EN1 is the lowest byte and it does show 0x04.  The bit was also set by loading the value at 0xE000E104, ORing it with 04, and then storing it back to 0xE000E104.

    I looked up PRIMASK in the Technical Reference Manual and sect 1.4.2.1 said that it, along with other core registers, "are not memory mapped and are accessed by register name, so the base address is not applicable and there is no offset.  Can you tell me how I can determine the value of PRIMASK?

    Also, are you aware of any applications that have a functioning watchdog timer that uses interrupts?  It might be helpful if I could look at one.

    Thank you,

    Brad

  • Hello Brad,

    I looked up PRIMASK in the Technical Reference Manual and sect 1.4.2.1 said that it, along with other core registers, "are not memory mapped and are accessed by register name, so the base address is not applicable and there is no offset.  Can you tell me how I can determine the value of PRIMASK?

    This should work for you:

        uint32_t ui32Ret;
    
        //
        // Read PRIMASK and enable interrupts.
        //
        __asm("    mrs     r0, PRIMASK\n"
              "    cpsie   i\n"
              "    bx      lr\n"
              : "=r" (ui32Ret));

    Also, are you aware of any applications that have a functioning watchdog timer that uses interrupts?  It might be helpful if I could look at one.

    Yes - C:\ti\simplelink_msp432e4_sdk_4_20_00_12\examples\nortos\MSP_EXP432E401Y\driverlib\watchdog_maskable_interrupt

    Best Regards,

    Ralph Jacobi