Errors in the Definitive Guide for ARM Cortex-M book series

Version 28

    Embarrassing to say, but just like any other technical documentation, there are a few errors in my books . Over the years I have learn a lot from my mistakes, but it is still impossible to catch all of the errors before the books are printed. In this document I summaries the errors I am aware of. This document will be updated from time to time as and when issues are found.

     

    Hope you enjoy the books.

    regards,

    Joseph

     

    Note: The page numbers are referring to the pages on paper copies. Some of the errors spotted in the early version of the the book are already fixed in some of the newer prints / electronic copies.

     

    The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors, 3rd edition

     

    Page
    Descriptions
    4

    Typo at bottom of page: "Intellectualy Property" should be "Intellectual Property"

    10Typo near bottom of page: "a wide range of coins on software development/debug tools" should be "a wide range of choices on software development/debug tools"
    38Near bottom of page: "A timer is need to" should be  "A timer is needed to"
    80

    Bottom of the page: "the setting of LSB in branch targets is handled by the compiler automatically" should be "the setting of LSB in branch targets is handled by the development toolchain automatically"

    (Note: In some tool chains this is handled by linker, and in some cases, e.g. gcc, the compiler invoke the linker and therefore the linking stage is hidden. So it is better to generalize by stating the toolchain handle this automatically.)

    83

    Typo at middle of page ("ERSR" should be "EPSR"):

    The EPSR cannot be accessed by software code directly using MRS (read as

    zero) or MSR

    94

    Table 4.7, second row

    0x90000000 + 0x90000000, result should be 0x20000000 (not 0x30000000)

    95The statement "In most cases, the instructions for saturation arithmetic are mnemonic starting with “Q,” for example “QADD16". If saturation occurred, the Q bit is set; otherwise, the value of the Q bit is unchanged." is inaccurate.

     

    The list of instruction that can set Q bit are QADD, QDADD, QSUB, QDSUB, SSAT, SSAT16, USAT, USAT16. Some other instructions start with Q (QADD8, QADD16, QASX, QSUB8, QSUB16, QSAX) and all instructions starting with UQ (UQADD8, UQADD16, UQSUB8, UQSUB16, UQASX, UQSAX) do not change the Q bit.

     

    Therefore the statement should be changed to:

    "In most cases, the instructions for saturation arithmetic are mnemonic starting with “Q,” for example “QADD16". If saturation occurred, the Q bit is set for the following instructions - QADD, QDADD, QSUB, QDSUB, SSAT, SSAT16, USAT, USAT16; otherwise, the value of the Q bit is unchanged."

    95

    4.3.3, first paragraph (or -> of)

    For SIMD instructions with 16-bit data, bit 0 and bit 1 are controlled by the result of lower half-word, and bit 2 and bit 3 are controlled by the result of upper half-word.

    100

    Figure 4.20, the order of POP instructions should be inverted of the order in PUSH. The corrected diagram is shown below:

    fig_4_20_stack_eg_1.jpg

    108Figure 4.26: Value in address 0x00 "Initial value of MPS" should be "Initial value of MSP"
    126

    Table 5.1: The directive for inserting instructions in GNU Assembler should be

    ".inst / .inst.n / .inst.w

    E.g., .inst.n 0xBE00"

    132MVN description: Should be "Move NOT" rather than "Move negative"
    135

    In the paragraph under table 5.6

    For example, if 0x83 is read in a LDRSB instruction, the value is converted into 0xFFFFFF83 before being placed in the destination register.

    136

    In the third paragraph in page 136 it should be

    "If the floating point unit is present, the instructions in Table 5.10 are also available to perform LDR and STR operations to the registers in the floating point unit."

    136

    On Page 136, in the third paragraph, "cannot be used with R15(PC) or R14(SP)."

    should be "... or R13(SP)."

    139

    On Page 139, in the fourth paragraph, "cannot be used with R15(PC) or R14(SP)."

    should be "... or R13(SP)."

    141

    Table 5.16: The text in the description column reference "Rd", instead of "Rn".

    141, 142

    Table 5.17, first column header

    "Example of Stack Operation" should be "Example of Multiple Load / Store for FPU registers".

    149

    Table 5.24, errors in comments for last two EOR instructions in the table

    EOR Rd, Rn,#immed ; Rd = Rn ^ #immed

    EOR Rd, Rn, Rm      ; Rd = Rn ^ Rm

    151

    REV16 mistyped as REVH:

    REV reverses the byte order in a data word, and REV16 reverses the byte order inside a half-word. For example, if R0 is 0x12345678, in executing the following:

    REV R1, R0

    REV16 R2, R0

    R1 will become 0x78563412, and R2 will be 0x34127856

    152

    REV16 mistyped as REVH:

    REVSH is similar to REV16 except that it only processes the lower half-word and then sign extends the result. For example, if R0 is 0x33448899, running:

      REVSH R1, R0

    R1 will become 0xFFFF9988.

    153

    Example for RBIT does not match descriptions:

    For example, if R0 is 0xB4E10C23 (binary value 1011_0100_1110_0001_0000_1100_0010_0011), executing:

        RBIT R0, R0

    R0 will become 0xC430872D (binary value 1100_0100_0011_0000_1000_0111_0010_1101).

    154

    Table 5.30, error in the operation descriptions in last two rows (AND should be XOR)

     

    TEQ <Rn>, <Rm>

    Test (bitwise XOR): Calculate XOR result between Rn and Rm. N bit and Z bit in APSR are updated but the XOR result is not stored. C bit can be updated if barrel shifter is used.

     

    TEQ <Rn>, #<immed>

    Test (bitwise XOR): Calculate XOR result between Rn and immediate data. N bit and Z bit in APSR are updated but the XOR result is not stored

    158

    Table 5.35 ("then" should be "than")

    GT  Signed greater than   Z flag is cleared, and either both N flag and V flag are set, or both N flag and V flag are cleared (Z == 0 and N == V)

    176

    Table 5.49

    Foot note 2 "Q bit is set when saturation occurs" is incorrect. This should be corrected to

    "These instructions do not set Q bit."

    178, 179

    Table 5.53

    Q bit is not set for the following instructions: QADD8, QADD16, QASX, QSUB8, QSUB16, QSAX,

    UQADD8, UQADD16, UQSUB8, UQSUB16, UQASX, UQSAX

    204

    Table 6.6 Data on AHB bus for ARM7TDMI

    Address, sizeBits 31-24Bit 23-16Bit 15-8Bit 7-0
    0x1000, wordData bits[31:24]Data bits[23:16]Data bits[15:8]Data bits[7:0]
    0x1000, half wordData bits[15:8]Data bits[7:0]
    0x1002, half wordData bits[15:8]Data bits[7:0]
    0x1000, byteData bits[7:0]
    0x1001, byteData bits[7:0]
    0x1002, byteData bits[7:0]
    0x1003, byteData bits[7:0]
    216

    Typo in BITBAND macro in the bottom of the page

    #define BIT BAND(addr,bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0xFFFFF)<<5)+(bitnum<<2))

    218 to 219

    Section 6.9 Memory access attributes

    Last sentence in page 218 should be

    "The Cacheable and Bufferable attributes are usually used by a cache controller, which specifies memory types and caching scheme, as shown in Table 6.11."

    247Figure 7.14 - "Entering the interrupt handler cause the active status to beset" should be "Entering the interrupt handler causes the active status to be set"
    253

    Table 7.9 CMSIS-Core symbol for Interrupt Priority Registers should be "IP", not "IR"

    NVIC->IP[0] to NVIC->IP[239]

    261

    Table 7.17 Width of VECTPENDING and VECTACTIVE incorrect.

    20:12 VECTPENDING

    8:0 VECTACTIVE

    Bit 21 and bit 9 are reserved.

    (Same issue for page e130, table F.9)

    265

    7.10.1 PRIMASK

    Typo near middle of the page: "PRIMARK" should be "PRIMASK"

    "In assembly language programming, you can change the value of PRIMASK register using CPS (Change Processor State) instructions:"

    306

    Errors in exclusive access example code for CMSIS-CORE - No need to have "&" in front of variable when using __LDREX and __STREX functions. For example,

        __LDREXW(&Lock_Variable) should have been __LDREXW(Lock_Variable)

    and

        status = __STREXW(1, &Lock_Variable);

    should have been

        status = __STREXW(1, Lock_Variable);

    315

    Table 9.8, reset value of SysTick Reload Value Register, and table 9.9, reset value of SysTick Current Value Register:

    In the architecture definition (ARMv7-M), the reset value of these two registers are unknown. However, in the actual implementation (in the current Cortex-M3 and Cortex-M4 processor designs), these two registers are reset to 0.

    Therefore the reset values in these two table should be changed to unknown, with a footnote added to these two tables : " * Architecturally the reset values is unknown, but in actual processor design the register is reset as 0. But this is not guarantee that it will be the same in future versions."

    329

    Typo in comments in example code (near middle of page)

    "ISB ; Execute and ISB after updating CONTROL" should be

    "ISB ; Execute an ISB after updating CONTROL"

    335

    In example code

       B __cpp(SVC_Handler_C)

    should have been

       B __cpp(SVC_Handler_main)

    336

    "For a system with only two tasks, the two tasks are executed alternatively, as shown in Figure 10.6."

    should be

    "For a system with only two tasks, the two tasks are executed alternately, as shown in Figure 10.6."

    335

    SVC with priority escalation lead to HardFault, not Usage Fault.

    "Because of the exception priority model, you cannot use SVC inside an SVC handler (because the priority us the same as the current priority). Doing so will result in a HardFault exception. For the same reason, you cannot use SVC in the NMI handler or the HardFault handler."

    356

    "If the MPU is not enabled, the processor no MPU is present."

    should be

    "If the MPU is not enabled, it behaves as the processor has no MPU."

    372

    In C example, function "mpu_enable(uint32_t options)", there is a typo in the comment

    void mpu_enable(uint32_t options)

    {

    MPU->CTRL = MPU_CTRL_ENABLE_Msk j options; // Enable the MPU

    __DSB(); // Ensure MPU settings take effects

    __ISB(); // Sequence instruction fetches using update settings

    return;

    }

    375

    Figure 11.6. Text in diagram has incorrect SRD values:

    Task A's SRD should be 11100000

    Task B's SRD should be 00000011

    377

    Table 11.2, Clarification in "Registers accesses"

    Please note that in Cortex-M7 processors, the MPU registers are word access only. Half word and Byte accesses are supported in Cortex-M3 and Cortex-M4 but this is not an architectural requirement.

    384

    The Usage Fault exception can be caused by a wide range of factors:

    "Execution of SVC when the priority Level of the SVC is the same or lower than current Level "

    this scenario lead to a HardFault not a Usage Fault.

    389

    Section 12.4.5, first sentence should be:

    "The programmer's model for the HardFault Status Register is shown in Table 12.6."

    425

    Section 13.2.8, typo in 2nd paragraph:

    FPFSCR should be FPDSCR.

    449

    Typo near bottom of the page:

    "For readers who would like to have a brief verview" -- should be overview.

    455

    Figure 14.7

    Second block on the botton left should be labelled ITM, not DWT.

    480Figure 14.20, typo in labels "Asynchornous FIFO" should be "Asynchronous FIFO".
    656

    First line of section "20.4.3 Accessing special registers" contains outdated information:

    "In the GNU toolchain, when accessing the special registers in assembly code, the name of the special registers must be in lower case". This is no longer the case, and has been fixed since 2007. See: Paul Brook - ARM uppercase MSR names

    Therefore the text should be changed to : "In recent version of the GNU toolchain, when accessing the special registers in assembly code, the name of the special registers can be in ether lower case or upper case, but not a mixture of lower/upper case."

    718

    Section 22.3, typo in description of q7

    • q7 - 8 bit fractional integers
    • q15 - 16 bit fractional integers
    • q31 - 32 bit fractional integers
    • f32 - 32 bit floating point
    754

    Example for re-entrant interrupt handler.

    Two addition steps might be needed

    1) to prevent a new re-entrant interrupt being triggered just before execution of SVC (I am still doing more check in this). To avoid the potential issue, set BASEPRI to the same level as the re-entrant interrupt (e.g. SysTick in this case) before SVC and clear BASEPRI inside the SVC Handler:

    2) for Cortex-M4 with FPU, also need to trigger the deferred lazy stacking

    __asm void SysTick_Handler(void)

    {

    #if (__CORTEX_M >= 0x04)

    #if (__FPU_USED == 1)

      ; The following 3 lines are for Cortex-M4 with FPU only

      TST  LR, #0x10 ; Test bit 4, if zero, need to trigger stacking

      IT   EQ

      VMOVEQ.F32  S0, S0  ; Trigger lazy stacking stacking

    #endif

    #endif

      ; Now we are in Handler mode, using Main Stack, and

      ; SP should be Double word aligned

      MRS  R0, PSR

      PUSH {R0, LR}       ; Need to save PSR and LR in stack

      ...

    SysTick_Handler_thread_pt

      BL    __cpp(Reentrant_SysTick_Handler)

      ; Block SysTick from being triggered just before SVC

      LDR  R0,=0xE000ED23 ; Address of SysTick priority level

      LDR  R0,[R0]

      MSR  BASEPRI, R0    ; Block SysTick from being triggered

      ISB                 ; Instruction Synchronisation Barrier

     

      SVC   0     ; Use SVC to return to original Thread

      B .       ; Should not return here

    __asm void SVC_Handler(void)

    {

      MOVS   R0, #0

      MSR    BASEPRI, R0  ; Enable SysTick again

      ISB    ; Instruction Synchronisation Barrier

    #if (__CORTEX_M >= 0x04)

    #if (__FPU_USED == 1)

      ; The following 3 lines are for Cortex-M4 with FPU only

      TST  LR, #0x10 ; Test bit 4, if zero, need to trigger stacking

      IT      EQ

      VMOVEQ.F32  S0, S0  ; Trigger lazy stacking stacking

    #endif

    #endif

      ; Extract SVC number

      TST    LR, #0x4 ; Test EXC_RETURN bit 2

      ITE    EQ ; if

      ...

    Please also note that the current code can only work if the re-entrant interrupt has the lowest priority compared to other interrupt sources.

    e6, e7

    Appendix A (A.2)

    Q bit is not set for the following instructions: QADD8, QADD16, QASX, QSUB8, QSUB16, QSAX,

    UQADD8, UQADD16, UQSUB8, UQSUB16, UQASX, UQSAX

    e18Figure B.4 - Q bit is not set by QADD16
    e19Figure B.5 - Q bit is not set by QADD8
    e22Figure B.8 - Q bit is not set by QSUB16
    e23Figure B.9 - Q bit is not set by QSUB8
    e24Figure B.10 - Q bit is not set by QASX
    e25Figure B.11 - Q bit is not set by QSAX
    e69

    Figure B.55 - Caption of the figure should be SMLALDX

    e74

    Figure B.60 - incorrect add / subtract path. It should be:

    SMLSLD.png

    e75

    Figure B.61, incorrect data routing in illustration. It should be

    SMLSLDX.png

    e76 to e79Figure B.63~B.68, the ROR #imm should be 0/8/16/24, not 8/16/32.
    e85Figure B.74 - the instruction above the figure should be "USUB16 ... " instead of "USUB168 ...".
    e93Figure B.84 - Q bit is not set by UQADD16
    e94Figure B.85 - Q bit is not set by UQADD8
    e95Figure B.86 - Q bit is not set by UQSUB16
    e96Figure B.87 - Q bit is not set by UQSUB8
    e97

    Figure B.88 - Q bit is not set by UQASX

    Wrong diagram used - QASX rather then UQASX. The correct one is as below:

    UQASX.jpg

    e98Figure B.89 - Q bit is not set by UQSAX
    e101 to e104Figure B.93~B.98 - the ROR #imm should be 0/8/16/24, not 8/16/32.
    e130Table F.9 Width of VECTPENDING and VECTACTIVE incorrect.

    20:12 VECTPENDING

    8:0 VECTACTIVE

    Bit 21 and bit 9 are reserved.

    (Same issue for table 7.17 on page 261)
    e140

    Table F.28, reset value of SysTick Reload Value Register, and table F.29, reset value of SysTick Current Value Register:

    In the architecture definition (ARMv7-M), the reset value of these two registers are unknown. However, in the actual implementation (in the current Cortex-M3 and Cortex-M4 processor designs), these two registers are reset to 0.

    Therefore the reset values in these two table should be changed to unknown, with a footnote added to these two tables : " * Architecturally the reset values is unknown, but in actual processor design the register is reset as 0. But this is not guarantee that it will be the same in future versions."

     

    Note: Due to the size of the book, the publisher had decided to remove the appendix in paper copies and put it on the web. This is now available for download on the Elsevier's website: http://booksite.elsevier.com/9780124080829/

     

     

     

    The Definitive Guide to the ARM Cortex-M3, 2nd edition

     

    Page
    Descriptions
    29 (3.2.1)Example for MRS  and  MSR: EPSR cannot be read. So you can only get 0 when executing "MRS  r0, EPSR"
    49 (table 4.6), 53MVN description: Should be "Move NOT" rather than "Move negative"
    59

    Table 4.21 text alignment issues:

    "ASRRd, Rn" should be "ASR    Rd, Rn"

    "LSLRd, #immed" should be "LSL    Rd, #immed"

    "LSLRd, Rn" should be "LSL    Rd, Rn"

    107"Internet Protocol providers" should be "IP (Intellectual Property) providers" (I blame the editor for this one )
    138

    Section 8.3 code example to set the priority to 0xC0:

    NVIC_SetPriority(7, 0xC0) should have been

    NVIC_SetPriority(7, 0xC)

    Note: The CMSIS call internally shift the priority level to implemented bits.

    142

    Table 8.12 SYSTICK Calibration Value Register

    TENMS field should be RO (read only), not R/W (read/write)

    178

    Example code (int LockDeviceA(void)):

    if (__LDREXW(&DeviceALocked) = 0) {

    Should be

    if (__LDREXW(&DeviceALocked) == 0) {

    205Example code for non-base thread enable need to be updated to handle double word stack alignment correctly (see example code for the new Cortex-M3/M4 book).
    249Table 15.1, C_HALT bit is reset by system reset, not power on reset.
    250

    Foot note for table 15.2

    "The control bit in DHCSR..." should be "The control bit in DEMCR..."

    262First paragraph: "Text Data Output (TDO)" should be "Test Data Output (TDO)".
    281Figure 17.5 "0.9 DMIP/MHz" should be "0.9 DMIPS/MHz"
    305

    Section 19.6 Using unsupported instructions

    ".word" should be changed to ".inst"

    355

    The following description of carry bit is incorrect:

    "A carry occurs

    • If the result of an addition is greater than or equal to 2^32

    • If the result of a subtraction is positive or zero

    • As the result of an inline barrel shifter operation in a move or logical instruction."

     

    The correct description is:

    "C is set in one of four ways:

     

    • For an addition, including the comparison instruction CMN, C is set to 1 if the addition produced a carry (that is, an unsigned overflow), and to 0 otherwise.
    • For a subtraction, including the comparison instruction CMP, C is set to 0 if the subtraction produced a borrow (that is, an unsigned underflow), and to 1 otherwise.
    • For non-addition/subtractions that incorporate a shift operation, C is set to the last bit shifted out of the value by the shifter.
    • For other non-addition/subtractions, C is normally left unchanged (but see the individual instruction descriptions for any special cases)."

    (Note: this error originated from ARM documentation - a defect has been raised)

    410

    Table D.6 SYSTICK Calibration Value Register

    TENMS field should be RO (read only), not R/W (read/write)
    415

    Table D.23 Usage Fault Status Register

    UNALIGNED bit description. The text said it can only be set if UNALIGN_TRP is set. This is incorrect. It can be set if an unaligned transfer is attempted for instructions that doesn't support unaligned transfers (e.g. LDMIA/STMIA).

    428Table E.6: DEBUGEVF should be DEBUGEVT

     

     

     

    The Definitive Guide to the ARM Cortex-M3, 1st edition

    Most of the most issues found are documented here. Please so see the errors in the second edition.

     

    The Definitive Guide to the ARM Cortex-M0, 1st edition

    (to be added)

    PageDescriptions
    4In figure 1.1 for processor IP there's a typo of Mail instead of Mali
    30

    Table 3.2, second row

    0x90000000 + 0x90000000, result should be 0x20000000 (not 0x30000000)

    30

    Typo in equations:

    // Calculating Z = X + Y, where X, Y and Z are all 64-bit

    Z[31:0] = X[31:0] + Y[31:0]; // Calculate lower word addition, carry flag get updated

    Z[63:32] = X[63:32] + Y[63:32] + Carry; // Calculate upper word addition

    40

    Table 4.4, end of row 2 (<device>.h) descriptions:

    "The actual filtername depends on the device." should be "The actual filename depends on the device."

    78Table 5.3 : In GNU Assembler, instruction should be delared using .inst rather than .word
    87

    Notes for PUSH instructions incorrectly described register layout ordering.

    For PUSH {<Ra>, <Rb>,...} instruction:

    SP is first updated to new SP value, and then:

    memory[new_SP    ] = Ra,

    memory[new_SP+4] = Rb,

    ...

    (The order of the register content is based on register's number, i.e. Lower register is push to the lower address in the stack).

    121

    Figure 6.8 - On page 121 in figure 6.8 "simple unsigned integer square root function" the diagram shows that when the check for "N = 0" fails the flow returns to "M = 0" which is incorrect.  The program flow should loop around to the step labelled "M = M + N". (Thanks Brendan M for pointing this out).

    fig_6_8_sqrt_correction.jpg

    137

    Last line of this page, the abbreviation of Write Back Write Allocate should be WBWA, not WBWT.

    146

    Figure 8.3:

    Typo in vector table : "Had Fault vector" should be "HardFault Vector"

    170

    Figure 9.4 : Wrong diagram - It is duplicated from figure 9.3. The correct image should be:

    fig_9_4_interrupt_pending_sw_clear.jpg

    Figure 9.4 : Interrupt pending status is cleared and is not taken by the processor.

    186

    At the bottom of the page, the last statement is incorrect. The correct descriptions should be:

    "The SysTick Calibrate Value Register can be used to provide information for calculating the desired reload value for the SysTick. If a timing reference is available on the microcontroller, the TENMS field in the register may provide the tick count for 10 milliseconds. In some Cortex-M0 microcontrollers a reference value is not available. Also some microcontrollers do not have an external reference clock source for the SysTick timer, in such case the NOREF bit is set to one to reflect this."

    327

    Example code for putting LPC1114 in low power mode.

    The bit definition for LPC_SYSCON->PDSLEEPCFG  is wrong in the code. You can program it as:

      LPC_SYSCON->PDSLEEPCFG = 0x000018BF;  // WD osc on, BOD off