Jump to content
spirilis

The Datasheet "Book Club"

Recommended Posts

Ok so this was an idea that came to mind last night; These datasheets and related documents are huge, and sometimes have surprising & interesting details nestled into their labyrinth-like chapters.  Why not start a thread for sharing noteworthy details?  No need to be a pack of lone wolves about these things...

 

I'll start - with the TM4C123GH6PM datasheet: http://www.ti.com/lit/ds/symlink/tm4c123gh6pm.pdf

 

Reading through Chapter 2 yesterday, "The Cortex-M4F Processor", a few details stuck out that I hadn't realized before-

 

1. Didn't realize there is a 16-bit SIMD vector processing unit.  How do you access/use it from GCC I wonder?

 

2. Debug - SWV, Serial Wire Viewer, is a feature where you can export a stream of software-generated messages, data trace, profiling information.  Software-generated messages -- How do we access that?  I assume we need OpenOCD to use this feature, but is there an API for writing to this debug interface?

 

3. Like most complicated processors, there is a notion of "privileged" vs "unprivileged" execution modes.  The Cortex-M4F extends this further by declaring two operational modes too--"Thread" mode (i.e. normal application runtime, either privileged or unprivileged) and "Handler" mode, exclusively privileged and only available as the context for ISR handlers.

 

4. Coming from MSP430 land, I'm always looking for analogies to the MSP430 in here.  The equivalent for the "GIE" (global interrupt enable) bit is the PRIMASK register; when bit0 is set, it disables all interrupts (of configurable priority, so RESET/NMI/Fault interrupts still fire).  This is important for sleep modes below...

 

5. Interrupt priorities run from 0-7, with *lower* numbers being of "higher" priority.  Default priority for all interrupts is 0 (the highest).  BASEPRI register declares the minimum priority required to fire, and besides setting 0 (=no exceptions masked), the setting masks all interrupts of that priority and those higher in number ("lower" in priority).

 

6. The CONTROL register has an interesting bit, "FPCA", which will adjust the latency for entering an interrupt ISR; it determines whether or not the Floating Point Unit's registers should be pushed onto the stack during ISR entry or not.  This makes a substantial difference, as seen on page 109; the difference between FPCA=1 exception frame and FPCA=0 exception frame is many-fold.  So folks not using floating point would do well to keep that disabled (not 100% sure how GCC handles this yet, i.e. whether there's a builtin, a TivaWare ROM_* function or if you have to do an inline ASM code).

 

7. Bit-banding is available for everything; flash, SRAM, peripherals.  I think TivaWare has some macros to make that easy, need to look into it.  It's a feature for doing single atomic writes or reads to a single bit of any byte in the address space, by writing/reading a 32-bit word (0x00000000 for bit 0, 0x00000001 for 1).
 

8. The Cortex-M4F provides two user IRQs for operating system support; SVCall (Supervisor Call) and PendSV (pendable, interrupt-driven request for system-level service--typically used for context switching).

 

9. Sleep modes.  The Cortex-M4F uses instruction-based sleep entries, but it has some features that allow the MSP430's "event driven" paradigm too.

9a. WFI = Wait For Interrupt, goes to sleep and will wake up only if an unmasked interrupt occurs.

** Sometimes waking requires a common "clean-up" or reinitialization routine to run; to support this, your app would enter WFI inside an idle loop with PRIMASK enabled so that the CPU wakes up, but does not enter the ISR right away; does its cleanup work; then disables PRIMASK so the Cortex immediately jumps to the highest-priority IRQ's ISR.

9b. WFE = Wait For Event, goes to sleep and will wake up if ANY interrupt occurs, even if it's masked; If it is masked, the CPU will not branch to its ISR but just continue from the point where the WFE instruction occurred.  If it is unmasked, then the CPU will jump to the ISR immediately.

9c. Sleep-on-Exit; if the SLEEPEXIT bit of SYSCTRL is set, then the CPU will return to sleep mode after servicing ISRs.  Similar to MSP430's LPM modes if the ISR does not issue a __bic_SR_register_on_exit(LPMx_bits); type of call.

 

That's all for now.  Chapter 3 later today.

Share this post


Link to post
Share on other sites

Ok so this was an idea that came to mind last night; These datasheets and related documents are huge, and sometimes have surprising & interesting details nestled into their labyrinth-like chapters.  Why not start a thread for sharing noteworthy details?  No need to be a pack of lone wolves about these things...

 

I'll start - with the TM4C123GH6PM datasheet: http://www.ti.com/lit/ds/symlink/tm4c123gh6pm.pdf

 

2. Debug - SWV, Serial Wire Viewer, is a feature where you can export a stream of software-generated messages, data trace, profiling information.  Software-generated messages -- How do we access that?  I assume we need OpenOCD to use this feature, but is there an API for writing to this debug interface?

Good stuff.

Pg 2, here has more information on Serial Wire Viewer. Basically real time viewer of variables through a back channel without stealing processor time.

Share this post


Link to post
Share on other sites

Chapter 3 was mostly snore-worthy.  Lots of fine details about SysTick, NVIC, MPU, FPU registers ..... that we usually don't have to deal with since TivaWare covers it I believe.  Anyone porting a 3rd party HAL/PDL API would want to read all that in detail though.

 

SysTick is the main thing and it's pretty simple; the TivaWare API is too.

 

The important thing is that SysTick is a 24-bit counter that starts *at* the STRELOAD value, and counts *down* to 0, interrupting when it hits 0.  I know with TivaWare the way you "reset" the counter is to force a reload using NVIC_ST_CURRENT_R = 1

Share this post


Link to post
Share on other sites

 

6. The CONTROL register has an interesting bit, "FPCA", which will adjust the latency for entering an interrupt ISR; it determines whether or not the Floating Point Unit's registers should be pushed onto the stack during ISR entry or not.  This makes a substantial difference, as seen on page 109; the difference between FPCA=1 exception frame and FPCA=0 exception frame is many-fold.  So folks not using floating point would do well to keep that disabled (not 100% sure how GCC handles this yet, i.e. whether there's a builtin, a TivaWare ROM_* function or if you have to do an inline ASM code).

 

 

I think this is (partially) controlled using calls in fpu.c

 

FPUStackingDisable(void) - Don't save FPU registers in ISR

FPULazyStackingEnable(void) - Leave space for FPU registers in stack frame, but only save if used

FPUStackingEnable(void) - Save FPU registers in ISR (whether ISR uses FP or not)

 

These control the ASPEN (and LSPEN ) bits in FPCC

 

startup_gcc has an incantation to enable the FPU, so I assume if not using FPU one could take that out, and turn off FPUStacking.

(Or if know ISRs won't use FP, then could turn off FPUStacking)

As far as how to turn off FPU in CCS - not so sure how/where.  (Enabling the FPU happens in CCS C initialization routine - _c_int00 )

Share this post


Link to post
Share on other sites

Hi,

Spirilis, congratulations for the idea, it is very good.

As for your comments, I have two small observations:

1) ref yours #2: as far as I know, up to now, on TI boards is implemented only JTAG interface ( ICDI knows only that) but seems to be changing on TM4C129 boards. Other providers (IAR, Segger) implemented both JTAG and SWD on their uLink2 devices.

2) ref yours #4: no, PRIMASK is not a replacement for global interrupt enable. This is still present and can/must be used with IntMasterEnable() function which is a wrapper to the asm instruction cpsie. The purpose of PRIMASK is to enhance the responsivity of application to real time events and to avoid disabling global interrupts, widely used in RTOSes. The feature is still not fully used by all RTOS authors. Now there are RTOSes which do not disable at all the global interrupt, improving the responsivness to real time events.

L

Share this post


Link to post
Share on other sites

As for SIMD, get the CMSIS library from Arm.  It provides intrinsics for SIMD, along with other useful libraries.

 

Also straight from Arm, two essential documents about the Cortex M4 series--

 

http://infocenter.arm.com/help/topic/com.arm.doc.ddi0439d/DDI0439D_cortex_m4_processor_r0p1_trm.pdf

http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/DUI0553A_cortex_m4_dgug.pdf

Share this post


Link to post
Share on other sites

2) ref yours #4: no, PRIMASK is not a replacement for global interrupt enable. This is still present and can/must be used with IntMasterEnable() function which is a wrapper to the asm instruction cpsie. The purpose of PRIMASK is to enhance the responsivity of application to real time events and to avoid disabling global interrupts, widely used in RTOSes. The feature is still not fully used by all RTOS authors. Now there are RTOSes which do not disable at all the global interrupt, improving the responsivness to real time events.

I'm a little confused by this description. AFAICT PRIMASK is exactly the Cortex-M version of MSP430's GIEn.

 

The CPS instruction does nothing but enable or disable either PRIMASK or FAULTMASK. TivaWare's IntMasterEnable() is a function that invokes "cpsie i", meaning it clears PRIMASK (as opposed to "cpsie f" which clears FAULTMASK, "cpsid i" which sets PRIMASK, etc.). This is exactly what __enable_irq() in <core_cmFunc.h> does except that __enable_irq() is inline and provides a memory barrier that's probably implicit in the IntMasterEnable() function call. __get_PRIMASK() is the standard way to determine whether interrupts are disabled.

 

There may be RTOSes that do not disable the global interrupt, but AFAICT they'd have to do that not by using PRIMASK but instead using the interrupt priorities infrastructure; this is a nice discussion of the issues encountered with this feature.

 

If I've gotten this wrong, could you provide more information?

Share this post


Link to post
Share on other sites

Hi,

@pabigot: again, you are right - after a second taught, yes, it is a global interrupt enable. It seems I over-reacted to the expression "global…" and failed to express the right things - taught is always faster than the hand - ...

 

The nice feature added is the BASEPRI register - this one helps to filter more the interrupts and allowing to work without disabling them, neither globally, neither individually.

 

Thanks for the link, I already know Miro's blog, but the last six month i did not opened.

 

Regards,

L

Share this post


Link to post
Share on other sites

A subset of the lessons I learned today (references are to the TM4C123GH6PM data sheet):

  • 5.2.6 "System Control" specifies a delay of 3 system clocks after a peripheral module clock is enabled in the SYSCTL->RCGCmodule register before the module registers are accessed. (A comment in driverlib/sysctl.c says five clock cycles.) Failure to satisfy this delay results in a HardFault.

     

    Unfortunately, gcc-arm doesn't have a __delay_cycles() function.

  • Today was my day to discover commit control (10.2.4) and the need to unlock PC0-PC3, PD7, and PF0 before setting AFSEL or DEN if you actually want a peripheral on those pins to work.
  • Much example code for the unlock process looks like:

    HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;
    HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;
    
    This isn't wrong, but the second assignment to LOCK is unnecessary because writing to CR automatically releases the lock (description of GPIOLOCK register on page 684).
It's annoying that the CMSIS structure declaration for the GPIO registers marks the CR register as read-only so you have to cast away the const in order to set the commit bits.

Share this post


Link to post
Share on other sites

If you look in driverlib/gpio.c GPIOPadConfigSet, you'll see the code setting DR2R, DR4R, DR8R as though these were additive, e.g. to get a 14 mA drive you'd set all three. Or as if it were necessary to explicitly clear the bits in undesired settings.

 

No. Per the datasheet, setting a bit in any one of the three clears that bit in the other two. <x>

 

Similarly, setting PUR clears the PDR bit, and vice-versa, so only one assignment is necessary to enable internal resistance. Two are necessary to clear both; ODR is not coupled to these capabilities.

 

This makes much more sense, and cuts the code length down considerably by removing those redundant clears if you aren't doing this inside a library routine with a variable configuration.

 

Summarizing my current understanding of the TM4C123 10.3 Initialization and Configuration steps:

 

(1) Enable the module port, if not done already. Wait 3 cycles after enabling.

(1.5) Unlock any bits in CR if necessary<a>

(2) Configure DIR if necessary<b>

(3) Configure AFSEL

(4) Set one of DR2R, DR4R, DR8R<c>

(5a) Set PUR or PDR, or clear both<d>

(5b) Configure ODR<d>

(5c) Configure SLR if using 8mA drive strength

(6) Configure DEN and (if necessary) AMSEL

(7) Configure interrupts (see details in 10.3 step 7)<e>

(8) Optionally restore the lock bit. Note that the description in 10.3 step 8 is misleading: this is not a bit in GPIOLOCK, it is a bit in GPIOCR which requires a set of the GPIOLOCK key before being modified.

 

Notes:

 

<a> Bits that are JTAG/SWD pins or NMI pins; see 10.2.4 and the GPIOLOCK and GPIOCR register descriptions. In library code you can simply check the CR bit: if it's clear, modifications require the unlock process.

 

<b> For some peripheral functions (e.g. UART) this bit is don't-care. See Table 10-3 "GPIO Pad Configuration Examples".

 

<c> It's unclear to me whether it is meaningful to set a zero mA drive strength by clearing a bit in all three registers, although this can be done.

 

<d> Table 10-3 suggests that ODR and PUR/PDR should be configured in certain cases regardless of direction, and should not be considered a "pick one of the three options" situation as implied by the description in section 10.3 step 5.

 

<e> Presumably interrupt configuration is relevant only when the pin is an input, but I can't find text confirming this.

 

<x> I wondered whether the driverlib code sets all the registers redundantly because it's faster than introducing jumps. Looking more closely, a comment states that some Tiva devices support 6mA, 10mA, and 12mA drive strengths, so it could be that somebody assumed that was how they're set. In fact, no: TM4C129 devices have extended drive, but the DR2R DR4R and DR8R registers are documented to behave the same as the TM4C123 ones. (edit) Driverlib code does actually appear to take the steps necessary to produce the alternative drive settings, but to be sure compare what it does against the corresponding initialization/configuration description in a TM4C129 datasheet.

Edited by pabigot

Share this post


Link to post
Share on other sites

Hello all

        1 small query regarding Table 10-1. GPIO Pins With Special Considerations

 

1. Here PA[1:0] has UART0 ( a peripheral function) but the AFSEL for these pins in the table is 0.

 

But in the description of GPIOAFSEL register: the corresponding bit is 1 for the pin to function as a peripheral function.

and it is mentioned as :

"The reset value for this register is 0x0000.0000 for GPIO ports that are not listed in Table 10-1 on page 650"

but when I downloaded a simple code the reset value for  PORTA  (which is listed in the table) was 0x0000.0000 

Share this post


Link to post
Share on other sites

Read through the Peripheral Driver Library's section on Controller Area Network (CAN) today while sipping coffee at a local coffeehouse. Neat peripheral, but I must say, the "examples" at the end of the chapter should be thrown in the trash. At some point when I care enough I'll go find the proper channels to report this to TI but it's got a contradiction or 2 and the "FIFO" example isn't even complete.

 

That said, the peripheral sounds pretty straightforward, although the clock setter piece takes a "source clock frequency" that the PDL manual mentions might be the System Clock, or it might be 8MHz max on some chips; but peeking the datasheets for the TM4C123GH6PM and TM4C1294NCPDT, I think both of those just take the main clock as the input, though I'm not 100% sure.

 

The peripheral has 32 "message objects" which are basically slots you can designate for receiving data (setting a filter if necessary) or sending, or you can set up an automated Remote-Frame-Request answerer. A cool feature is FIFO mode; you can set up an arbitrary-length FIFO for a particular message ID by setting a number of message objects to the same filter, but with MSG_OBJ_FIFO set for the first N-1 message objects, leaving the last one without the MSG_OBJ_FIFO flag. What happens is the CAN peripheral will send new data to the first message object matching that filter but with the NEWDAT bit cleared, so that new data will continue to skip over FIFO members that are full, until it gets to the last one; if the last one already has data (NEWDAT bit set) and new data comes in, the new data will overwrite it. Likewise it looks like you read in sequence; from lowest message object# to highest, since lower message object #'s have higher priority. Reading clears the NEWDAT bit so it's eligible to receive new data.

 

I have a pair of CAN BoosterPacks ready, one for MSP430 + MCP2515 and the other is soldered up to use the Tiva-C TM4C123 LaunchPad's CAN0 peripheral, so I'll be experimenting with this soon.

Share this post


Link to post
Share on other sites

Today's research is on Cortex-M sleep modes and interrupt handling. I'm still digesting the bulk of it, but the short form is there are three common operational modes (RUN, SLEEP, DEEP SLEEP) that are implemented through Cortex-M instructions WFI/WFE and bits in the SCR. (Anything lower than DEEP SLEEP, like "hibernate" or EM3/EM4, is probably vendor-specific). Based on a sample size of two (TM4C and EFM32), RUN and SLEEP are simple, but DEEP SLEEP can reconfigure your processor and peripheral clocks back to their power-up defaults. PRIMASK plays an important role in this too, if you want to be sure all interrupts are handled before you commit to sleeping. (Which you probably do, if what your interrupts do includes assumptions that the clocks are configured in a particular way.)

 

The "book-club" relevant part is that section 5.2.6 "System Control" of the TM4C123GH6PM datasheet clearly specifies that software must confirm the EEPROM is not busy prior to entering either SLEEP or DEEP SLEEP. TivaWare's ROM_SysCtl*Sleep and CPUwfi() don't do this explicitly, though many of the EEPROM_* commands do check EEPROM.EEDONE before returning. Keep this in mind if you happen to be mucking with the EEPROM just before going to sleep, say, maybe to save some state in non-volatile memory.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×