I'm working on a K61 Cortex M4 controller and trying to access the watchdog timer output registers (0x40052000). I have several interrupt running, so reading the 16 bit register WDOG_TMROUTH and WDOGTMROUTL separately will sometimes cause a jump in value.

I want to know if it is possible to reading the WDOG_TMROUTH and WDOGTMROUTL register as a 32 bit access. I tried the following code

time = *((unsigned long*)(&WDOG->TMROUTH));

compiled to LDR in assembly. When the program reach the above code, it triggers a system hard fault.

When I modify the code to be a 16 bit access instead of 32 (compiled to LDRH in assembly), the assignment works fine.

I wonder if watchdog register specifically forbids 32 bit access (to the point where they flipped register's high and low order)?

It is not allowed to read the WDOG_TMROUTH and WDOG_TMROUTL as a single long word access - you must read it as two 16 bit accesses. The access restriction is valid for all registers in the WDOG peripheral (byte reads are allowed but make no sense).

You could place a disabled and enable interrupt around the two register reads to avoid interrupts interrupting the two access but there is still a small risk that there will be a count beftween the two accesses that causes a jump.

I would do this:

unsigned long fnGetWDOG_cnt(void)

unsigned short usWDLow ;

unsigned short usWDHigh;

do {

usWDHigh = WDOG_TMROUTH;

usWDLow = WDOG_TMROUTL;

} while (usWDHigh != WDOG_TMROUTH);

return ((usWDHigh << 16) | usWDLow);

which will repeat the read in case there is an increment of the higher register during the read, thus guaranteeing that the returned value is accurate at the time of the low count register access.

It is not allowed to read the WDOG_TMROUTH and WDOG_TMROUTL as a single long word access - you must read it as two 16 bit accesses. The access restriction is valid for all registers in the WDOG peripheral (byte reads are allowed but make no sense).

You could place a disabled and enable interrupt around the two register reads to avoid interrupts interrupting the two access but there is still a small risk that there will be a count beftween the two accesses that causes a jump.

I would do this:

unsigned long fnGetWDOG_cnt(void)

unsigned short usWDLow ;

unsigned short usWDHigh;

do {

usWDHigh = WDOG_TMROUTH;

usWDLow = WDOG_TMROUTL;

} while (usWDHigh != WDOG_TMROUTH);

return ((usWDHigh << 16) | usWDLow);

which will repeat the read in case there is an increment of the higher register during the read, thus guaranteeing that the returned value is accurate at the time of the low count register access.