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.

MSPM0G3507: Is there any example for MPU control and where are the MPU control APIs?

Part Number: MSPM0G3507

Tool/software:

Hello,

I am trying to access to the stack to check its overflow. I causes entering default handler. I guess it is because the stack space is protected by MPU.

Does the application have the chance to enter Handler mode? (Is the internal CONTROL register accessible for the application?)

Where are the APIs for Cortex-M0+ which is using Arm6-M? I only find mpu_armv7.h. But MSPM0 uses Arm6-M. And is there any examples?

Thanks!

Crane

  • Please check these two examples. The MPU is used paired with IQmath

  • Hi Eason,

    Thanks for your reply.

    I checked both example and didn't see that they use MPU. Both examples just did a calculation. The attached are what I got.


    mathacl_mpy_div_op.c
    /*
     * Copyright (c) 2021, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include "ti_msp_dl_config.h"
    
    /* OP1 = 0.5, 0.5 x 2^31 = 1,073,741,824 = 0x4000 0000 */
    #define OP1_Q31 (0x40000000)
    /* OP2 = 0.3, 0.3 x 2^31 = 644,245,094 = 0x2666 6666 */
    #define OP2_Q31 (0x26666666)
    /* OP3 = 15, 15 x 2^18 = 3,932,160 = 0x3C 0000 */
    #define OP3_Q18 (0x003C0000)
    /* OP4 = 4, 4 x 2^18 = 1,048,576 = 0x10 0000 */
    #define OP4_Q18 (0x00100000)
    
    const DL_MathACL_operationConfig gMpyConfig = {
        .opType      = DL_MATHACL_OP_TYPE_MPY_32,
        .opSign      = DL_MATHACL_OPSIGN_UNSIGNED,
        .iterations  = 1,
        .scaleFactor = 0,
        .qType       = DL_MATHACL_Q_TYPE_Q31};
    
    const DL_MathACL_operationConfig gDivConfig = {
        .opType      = DL_MATHACL_OP_TYPE_DIV,
        .opSign      = DL_MATHACL_OPSIGN_UNSIGNED,
        .iterations  = 0,
        .scaleFactor = 1,
        .qType       = DL_MATHACL_Q_TYPE_Q18};
    
    
    int main(void)
    {
        volatile uint32_t mpyRes __attribute__((unused));
        volatile uint32_t divResultQuotient __attribute__((unused));
        volatile uint32_t divResultRemainder __attribute__((unused));
    
        SYSCFG_DL_init();
    
        /* Setup unsigned multiply operation, OP1 = 0.5, OP2 = 0.3 */
        DL_MathACL_startMpyOperation(MATHACL, &gMpyConfig, OP1_Q31, OP2_Q31);
        DL_MathACL_waitForOperation(MATHACL);
    
        /* Get result -- floating point Q31 equivalent of 0.15 = 0x1333 3333 */
        mpyRes = DL_MathACL_getResultOne(MATHACL);
    
        /* Divide result OP3 = 15 by OP4 = 4 */
        DL_MathACL_startDivOperation(MATHACL, &gDivConfig, OP3_Q18, OP4_Q18);
        DL_MathACL_waitForOperation(MATHACL);
        /* Get result -- floating point Q31 equivalent of 3.75 = 0xF 0000, remainder = 0 */
        divResultQuotient  = DL_MathACL_getResultOne(MATHACL);
        divResultRemainder = DL_MathACL_getResultTwo(MATHACL);
    
        /*
         * Stop at the break point to examine and verify the outputs:
         *   mpyRes = 0.15 (0x1333 3333)
         *   divResultQuotient = 3.75 (0x000F 0000)
         *   divResultRemainder = 0
         */
    
        DL_GPIO_clearPins(
            GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
        __BKPT(0);
    
        while (1) {
            __WFI();
        }
    }
    


    mathacl_trig_op.c
    /*
     * Copyright (c) 2021, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, plaintext, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include "ti_msp_dl_config.h"
    
    const DL_MathACL_operationConfig gSinOpConfig = {
        .opType      = DL_MATHACL_OP_TYPE_SINCOS,
        .opSign      = DL_MATHACL_OPSIGN_UNSIGNED,
        .iterations  = 10,
        .scaleFactor = 0,
        .qType       = DL_MATHACL_Q_TYPE_Q31};
    
    int main(void)
    {
        volatile uint32_t op1Cos __attribute__((unused));
        volatile uint32_t op1Sin __attribute__((unused));
        volatile uint32_t op2Cos __attribute__((unused));
        volatile uint32_t op2Sin __attribute__((unused));
        volatile uint32_t op3Cos __attribute__((unused));
        volatile uint32_t op3Sin __attribute__((unused));
    
        /*
         *                            Operation 3
         *                               0, 1
         *                                |
         *                                |      ^ Operation 2 -- .707, .707
         *                                |
         *                                |
         *                      ----------|---------- 1, 0     Operation 1
         */
    
        SYSCFG_DL_init();
    
        /* Original setup operation, plus first operation with OP1 = 0 degrees */
        /* Cos(0) = 1, Sin(0) = 0 */
        DL_MathACL_startSinCosOperation(MATHACL, &gSinOpConfig, 0);
        DL_MathACL_waitForOperation(MATHACL);
        op1Cos = DL_MathACL_getResultOne(MATHACL);
        op1Sin = DL_MathACL_getResultTwo(MATHACL);
    
        /* Re-use existing configuration with new OP OP1 = 45 degrees */
        /* Cos(45) = ~0.707, Sin(45) = ~0.707 */
        DL_MathACL_startSinCosOperation(MATHACL, &gSinOpConfig, 0x20000000);
        DL_MathACL_waitForOperation(MATHACL);
        op2Cos = DL_MathACL_getResultOne(MATHACL);
        op2Sin = DL_MathACL_getResultTwo(MATHACL);
    
        /* Re-use existing configuration with new OP OP3 = 90 degrees */
        /* Cos(90) = 0, Sin(95) = 1 */
        DL_MathACL_startSinCosOperation(MATHACL, &gSinOpConfig, 0x40000000);
        DL_MathACL_waitForOperation(MATHACL);
        op3Cos = DL_MathACL_getResultOne(MATHACL);
        op3Sin = DL_MathACL_getResultTwo(MATHACL);
    
        /*
         * Stop at the break point to examine and verify the outputs:
         *   op1Cos = should be 1 (0x7FFFFFFF)
         *   op1Sin = 0
         *   op2Cos = 0.707 (0x5A89E374)
         *   op2Sin = 0.707 (0x5A7B0D41)
         *   op3Cos = 0
         *   op3Sin = should be 1 (0x7FFFFFFF)
         */
    
        DL_GPIO_clearPins(
            GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
    
        __BKPT(0);
    
        while (1) {
            __WFI();
        }
    }
    

    Regards,

    Crane

  • Sorry, I make a misunderstand for the MPU. As this is a pure peripheral for ARM CPU, we don't provide an example.

    I find an exmple internally after referring to my colleague. Please check it.

    C_G3507_MPU.zip

  • Thanks Eason!

    It seems that probably the APIs from mpu_armv7.h works for MCU as well.

    Another question comes up. 

    I am setting the Access Permission for all regions full access for both privileged and unprivileged as in the example. (MPU_RASR register AP value is 011).

    I changed the sub-region control to "all enabled". (MPU_RASR register SRD bits are all 0).

    But it works to access to RAM only when the privileged is enabled as in the example. (MPU_CTRL register PRIVDEFENA bit is 1).

    My understanding is as long as AP and SRD are set as "full access" for RAM region, RAM should be accessible no matter if privileged is enabled in MPU Control register or not. 

    Any my experience is that SRD doesn't have the control no matter the whole 8 sub-regions are set as 0 or 1.

    Is my understanding not correct or is there anything I missed. 

    Thanks!

    Crane

  • Sorry, As I said this code is from my colleague. Here is the reply from Chatgpt:

    Based on your observations, it seems that the behavior you are experiencing is related to the PRIVDEFENA bit in the MPU_CTRL register. If the PRIVDEFENA bit is set to 1, the default memory map for privileged mode will be used, which might restrict access to the RAM region. To allow full access to the RAM region for both privileged and unprivileged modes, you may need to ensure that the PRIVDEFENA bit is set to 0.

    My suggestion is that:

    1. Check whether it helps when PRIVDEFENA =0

    2. In debug mode check whether the register is set correct.

  • I tried already and when this bit (PRIVDEFENA) is set 0, access to that specific RAM apace will cause a fault. When it is set 1, it works fine to access to RAM.

    Here are the values of the MPU registers:

    The first region #0 is RAM as in the example. The its RBAR and RASR are written correctly.

    Thanks!

    Crane

  • So, I think the problem is solved right?

  • No it stays the same.

    From my understanding, RAM should be accessible as long as the region is set full access (AP 011) and its sub-regions are enabled (SRD 0 for particular sub-region), no matter if the privilege mode is enabled or not (PRIVDEFENA 0 or 1).

    But right not, only when the privilege mode is enabled (PRIVDEFENA 1), the RAM can be accessed. Once it is disabled, accessing the RAM could always cause a fault no matter how AP and SRD are set.

    Yesterday, I read back the real values of these MPU registers to confirm if they are set correctly. From the result in the screenshot in last post, they are set as the value I want to set. 

    (In the configuration, RAM is the 1st region. From the screenshot, RAM region is set "full access" (AP is 0x3) and its SRD is 0xC0.

    Accessing to 0x20207C00 causes fault and it is understandable as the sub-region's SRD where 0x20207C00 is at is 1.

    But, accessing to 0x20202000 also causes fault. I don't understand why this also cause fault as its SRD is 0.

    At the same setting, I also tried to change the whole RAM's SRD to 0x00 to enabled all sub-regions, but accessing to 0x20207C00 still cause fault.

    Still, my question is, is my understanding on how the AP, SRD, PRIVDEFENA control on the region works not correct, or is there any missing in configuring these registers?

    Thanks!

    Crane

  • Hi Crane,

    I used to do the test with the MPU demo. what I test refers to below: (Project optimization level is set as "0")

    #include "ti_msp_dl_config.h"
    
    #define     MAIN_SRAM_BASE_ADDRESS      (0x20200000U)
    #define     MAIN_SRAM_TEST_ADDRESS      (0x20204000U)
    #define     MAIN_FLASH_BASE_ADDRESS     (0x00000000U)
    #define     MAIN_FLASH_TEST_ADDRESS     (0x00002000U)
    
    /* 32-bit data to write to flash */
    uint32_t gData32 = 0x12345678;
    uint32_t rData32 = 0;
    
    volatile DL_FLASHCTL_COMMAND_STATUS gCmdStatus;
    
    /* Codes to understand where error occured */
    volatile uint8_t gErrorType = 0;
    
    #define NO_ERROR 0
    #define ERROR_ERASE 1
    #define ERROR_8BIT_W 2
    #define ERROR_16BIT_W 3
    #define ERROR_32BIT_W 4
    #define ERROR_64BIT_W 5
    
    /* SRAM absolute address variable */
    uint32_t ramData __attribute__((location(MAIN_SRAM_TEST_ADDRESS))) = 0x1;
    
    /* MPU TEST function */
    void FLASH_TEST(void);
    void SRAM_TEST(void);
    void PERI_TEST(void);
    
    int main(void)
    {
    
        SYSCFG_DL_init();
    
        /* Default is privileged mode in thread mode*/
        /* IMPORTANT: Only privileged software can write to the CONTROL register to change the privilege level for software execution in Thread mode. */
    //    __set_CONTROL(__get_CONTROL() & ~CONTROL_nPRIV_Msk);
    
        /* Disable MPU */
        ARM_MPU_Disable();
    
        /*------------------------------------------*/
        /* Configure Flash Region */
        /* Region 0 - Device Type, Instruction access disable, No data access permission */
        MPU->RBAR = ARM_MPU_RBAR(0, MAIN_FLASH_BASE_ADDRESS);
        MPU->RASR = ARM_MPU_RASR_EX(1, ARM_MPU_AP_NONE, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_128KB);
    
        /* Region 1 - Device Type, Instruction access enable, Data access permission-Privileged access */
        MPU->RBAR = ARM_MPU_RBAR(1, MAIN_FLASH_BASE_ADDRESS);
        MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_PRIV, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_64KB);
    
        /* Region 2 - Normal Type, Instruction access enable, Data access permission-Full */
        MPU->RBAR = ARM_MPU_RBAR(2, MAIN_FLASH_BASE_ADDRESS);
        MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_NORMAL(1,1,0), 0, ARM_MPU_REGION_SIZE_32KB);
    
        /*------------------------------------------*/
        /* Configure SRAM Region */
        /* Region 3 - Normal Type, Instruction access enable, Data access permission-Privileged read only */
        MPU->RBAR = ARM_MPU_RBAR(3, MAIN_SRAM_BASE_ADDRESS);
        MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_NORMAL(1,1,0), 0, ARM_MPU_REGION_SIZE_32KB); // 0KB-32KB Full Access
    
        MPU->RBAR = ARM_MPU_RBAR(4, MAIN_SRAM_TEST_ADDRESS);
        MPU->RASR = ARM_MPU_RASR_EX(0, ARM_MPU_AP_PRO, ARM_MPU_ACCESS_NORMAL(1,1,0), 0, ARM_MPU_REGION_SIZE_8KB);   // 16KB-24KB SRAM read only
    
        /*------------------------------------------*/
        /* Configure Peripheral Region */
        /* Region 4 - Device Type, Instruction access disable, Data access permission-Full */
        MPU->RBAR = ARM_MPU_RBAR(5, GPIOA_BASE);
        MPU->RASR = ARM_MPU_RASR_EX(1, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_8KB);
    
        /* Region 5 - Device Type, Instruction access disable, Data access permission-Privileged access */
        MPU->RBAR = ARM_MPU_RBAR(6, GPIOB_BASE);
        MPU->RASR = ARM_MPU_RASR_EX(1, ARM_MPU_AP_PRIV, ARM_MPU_ACCESS_DEVICE(0), 0, ARM_MPU_REGION_SIZE_8KB);
    
        /*------------------------------------------*/
        /* Enable MPU */
        /* Enables use of the default memory map as a background region for privileged software accesses. */
        ARM_MPU_Enable(0x5);
    
        /*------------------------------------------*/
        /* TEST MPU Access */
    //    FLASH_TEST();
    //    SRAM_TEST();
    //    PERI_TEST();
    
        while (1) {
        }
    }
    
    void HardFault_Handler(void){
        /* Enter an infinite loop. */
        while (1) {
        }
    }
    
    void FLASH_TEST(void){
    
        /*---------------FLASH TEST-----------------*/
    
        /* Unprotect sector in main memory with ECC generated by hardware */
        DL_FlashCTL_unprotectSector(
            FLASHCTL, MAIN_FLASH_TEST_ADDRESS, DL_FLASHCTL_REGION_SELECT_MAIN);
        /* Erase sector in main memory */
        gCmdStatus = DL_FlashCTL_eraseMemoryFromRAM(
            FLASHCTL, MAIN_FLASH_TEST_ADDRESS, DL_FLASHCTL_COMMAND_SIZE_SECTOR);
        if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
            /* If command was not successful, set error flag */
            gErrorType = ERROR_ERASE;
        }
    
        if (gErrorType == NO_ERROR) {
            /* 32-bit write to flash in main memory with ECC generated by hardware */
            DL_FlashCTL_unprotectSector(
                FLASHCTL, MAIN_FLASH_TEST_ADDRESS, DL_FLASHCTL_REGION_SELECT_MAIN);
            gCmdStatus = DL_FlashCTL_programMemoryFromRAM32WithECCGenerated(
                FLASHCTL, MAIN_FLASH_TEST_ADDRESS, &gData32);
            if (gCmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) {
                /* If command was not successful, set error flag */
                gErrorType = ERROR_32BIT_W;
            }
        }
    
        unsigned int flashRead_8KB = *(unsigned int *)(MAIN_FLASH_TEST_ADDRESS);
        rData32 = flashRead_8KB;
    
        __BKPT(0);  // Flash write-read pass at 0x2000 (8KB)
    
        unsigned int flashRead_32KB = *(unsigned int *)(4*MAIN_FLASH_TEST_ADDRESS);
    
        __BKPT(0);  // Flash read pass at 0x8000 (32KB)
    
        unsigned int flashRead_64KB = *(unsigned int *)(8*MAIN_FLASH_TEST_ADDRESS);
    
        __BKPT(0);  // Flash read at 0x10000 (64KB) -> expected to trigger hardfault
    
        /*------------------------------------------*/
    }
    
    void SRAM_TEST(void){
    
        /*---------------SRAM  TEST-----------------*/
    
        rData32 = ramData;
        __BKPT(0);  // SRAM read pass at 0x20204000 (16KB)
    
    //    ramData = 0x2;
    //    __BKPT(0);  // SRAM write at 0x20204000 (16KB) -> expected to trigger hardfault
    
        __set_CONTROL(__get_CONTROL() | CONTROL_nPRIV_Msk); // Unprivileged thread mode
        rData32 = 2;
        __BKPT(0);  // SRAM write pass at &rData32
    
        rData32 = ramData;
        __BKPT(0);  // SRAM read at 0x20204000 (16KB) -> expected to trigger hardfault
    
        /*------------------------------------------*/
    }
    
    void PERI_TEST(void){
    
        /*-------------Peripheral TEST--------------*/
    
        __set_CONTROL(__get_CONTROL() | CONTROL_nPRIV_Msk); // Unprivileged thread mode
        DL_GPIO_reset(GPIOA);
        DL_GPIO_enablePower(GPIOA);
        delay_cycles(POWER_STARTUP_DELAY);
        __BKPT(0);  // GPIOA operation pass
    
        DL_GPIO_reset(GPIOB);
        DL_GPIO_enablePower(GPIOB);
        delay_cycles(POWER_STARTUP_DELAY);
        __BKPT(0);  // GPIOB operation -> expected to trigger hardfault
    
        /*------------------------------------------*/
    }
    

    In the SRAM_TEST, I can access to the full-access sram value (0x20200000) in unprivileged mode.

    If you set a higher order of the access type, then it will overwrite your lower order setting (If the address have overlapping). The 1st order is the lowest priority.

    Maybe you can check this part.

    B.R.

    Sal

  • Hi Sal,

    I realize that the fault is not caused when accessing RAM, but when returning from the MPU init function. The function is like this:

    void drvMpu_init(void)
    {
        uint32_t i;
    
        __DMB(); // Make sure outstanding transfers are done
    
        MPU->CTRL = 0; // Disable the MPU
    
        for ( i= 0; i < 4; i ++)
        { // Configure only 4 regions
            MPU->RNR = i; // Select which MPU region to configure
            MPU->RBAR = mpu_RBAR_config[i]; // Configure region base address register
            MPU->RASR = mpu_RASR_config[i]; // Configure region attribute and size register
        }
    
        for (i = 4; i < 8; i ++)
        {// Disabled unused regions
            MPU->RNR = i; // Select which MPU region to configure
            MPU->RBAR = 0; // Configure region base address register
            MPU->RASR = 0; // Configure region attribute and size register
        }
    
        MPU->CTRL = MPU_CTRL_ENABLE_Msk; // Enable the MPU
        //MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; // Enable the MPU and privileged access
        __DSB(); // Memory barriers to ensure subsequence data & instruction
        __ISB(); // transfers using updated MPU settings
    }

    When the privilege mode is enabled, it works fine to return from this function and access to RAM later.

    But if the privilege mode is not abled, the fault would be caused right after returning from this function to main function. Why does this happen?

    From the original example shared by Eason, I don't find that this function is called in it. I am wondering if there is any issue with this function when the privilege mode is not enabled.

    Thanks!

    Crane

  • Hi Crane,

    I suppose access MPU in unprivileged mode is invalid. Line 7 will cuase the hardfault. The same result also happens in my test code.

    B.R.

    Sal

  • I checked the arm documents, it has clarified in the user guide:

    So, the MPU should be inside the limited access memory.

    B.R.

    Sal

  • Hi Sal,

    I found why a hard fault is caused right after the function returns. It is not because of line 7, but because the stack accessibility.

    Here are how the regions are set:

        0x20200000,     //RAM: 32KB
        0x00000000,     //Flash: 128KB
        0x400A0000,    //Peripheral: 64KB
        0x400C0000,    //FlashCTL: 64KB
        0x20207800,     //Stack: 2KB

    If the stack region is set full access, but all sub-regions are disabled and the privilege level is NOT enabled, then a hard fault will be caused immediately after the function returns.

    If the stack region is set full access, all sub-regions are enabled but the privileged level is NOT enabled, the function can return successfully, but later access to stack will still cause a hard fault.

    Finally the question is narrowed down to this:

    Why the stack is still not accessible even when the stack region is set full access (AP = 3), its sub-regions are all enabled (SRD = 0x00) and the privileged is not enabled? Is this region protected by something else other than MPU protection?

    Here is the MPU configuration for all regions.

    Region 0: MPU_RBAR: 0x20200000 MPU_RASR: 0x0302C01D       -> RAM
    Region 1: MPU_RBAR: 0x00000001 MPU_RASR: 0x0302C021        -> Flash
    Region 2: MPU_RBAR: 0x400A0002 MPU_RASR: 0x0301011F        -> Peripherals
    Region 3: MPU_RBAR: 0x400C0003 MPU_RASR: 0x0301001F        -> Flash control
    Region 4: MPU_RBAR: 0x20207804 MPU_RASR: 0x03020015         -> stack in RAM

    Region 4 is stack (0x20207800 ~ 0x20208000). It should be accessible at unprivileged level. But not.

    Thanks!

    Crane

  • Hi Crane,

    I would test on stack and feedback to you.

    By the way, where do you enter the unpreviliged mode?

    B.R.

    Sal

  • Hi Sal,

    I found the issue. It is not because the stack is not accessible, but because of something else about printf(). If I use my own printf(), a hard fault would be caused when calling string functions, like strlen(), strcpy(). I am wondering how the privilege mode affects the execution of printf() and strlen(). The stack size is big enough for printf(). Any idea?

    I tried to track down. AS setting break points are not working in this piece of code, I can't confirm which statement caused this yet.

        tempMsg[0U] = '\0';
        for(uint32_t i=0; i<CONSOLE_BUFFER_LEN; i++) {
            tempMsg[i] = '\0';
        }
    
        len = strlen(message);
        strncpy(oldMsg, message, len);

    If I don't use printf at all (both from string.h and my own), a hard fault would still be caused when returning from this function:

    __STATIC_INLINE uint32_t DL_SPI_getRawInterruptStatus(
        SPI_Regs *spi, uint32_t interruptMask)
    {
        return (spi->CPU_INT.RIS & interruptMask);
    }

    By the way, the way to enter the unprivileged mode is to enable MPU only, not enable privileged mode, which is to choose line 23 and comment out line 24.

    Thanks!

    Crane

  • Hi Crane,

    By the way, the way to enter the unprivileged mode is to enable MPU only, not enable privileged mode, which is to choose line 23 and comment out line 24.

    Line 24 is used to set the default memory map as a background region for privileged software accesses. If not set, an access will cause hardfault in privileged mode.

    For entry the unpriviledge mode, below code could apply:

    // __set_CONTROL(__get_CONTROL() & ~CONTROL_nPRIV_Msk); // Privileged thread mode, not work in unpriviledge mode
    // __set_CONTROL(__get_CONTROL() | CONTROL_nPRIV_Msk); // Unprivileged thread mode

    If I don't use printf at all (both from string.h and my own), a hard fault would still be caused when returning from this function:

    It is expected if you comment out line 24, it is a flash region (SPI), access to it will trigger hardfault if you do not define the default memory map as a background region for privileged software accesses. If comment out line 23 and use line 24, it will trigger hardfault in unprivileged mode only.

    I tried to track down. AS setting break points are not working in this piece of code, I can't confirm which statement caused this yet.

    I would suggest you test with step running, this will let the code start step by step, and then you can narrow down the range. (you can entry disassembly step run).

    Region 0: MPU_RBAR: 0x20200000 MPU_RASR: 0x0302C01D       -> RAM

    Here you set 1100 0000 to SRD, then last 8KB is disable.

    Region 4: MPU_RBAR: 0x20207804 MPU_RASR: 0x03020015         -> stack in RAM

    Here you set 2KB for stack. then the 24KB-30KB in SRAM is with default memory map if you use line 24. If use line 23, then hardfault will trigger when you access it in both mode.

    Maybe you can check your code whether it access undefined region.

    B.R.

    Sal

  • Thanks Sal for your detailed reply.

    I think the issue comes from the understanding of the bit PRIVDEFENA in MPU_CTRL.

    Here is the description in the user guide:

    If I choose line 23, PRIVDEFENA will be 0. The the default memory map will be disabled. Then, if I specify all the regions like this:

    Region 0: MPU_RBAR: 0x20200000 MPU_RASR: 0x0302001D
    Region 1: MPU_RBAR: 0x00000001 MPU_RASR: 0x03020021
    Region 2: MPU_RBAR: 0x400A0002 MPU_RASR: 0x0301001F
    Region 3: MPU_RBAR: 0x400C0003 MPU_RASR: 0x0301001F
    Region 4: MPU_RBAR: 0x20207804 MPU_RASR: 0x03020015
    Region 5: MPU_RBAR: 0x20206005 MPU_RASR: 0x03020015
    Region 6: MPU_RBAR: 0x00000006 MPU_RASR: 0x00000000
    Region 7: MPU_RBAR: 0x00000007 MPU_RASR: 0x00000000

    The result is that SPI access will still cause a hard fault. 

    And If I use my own printf(), it also causes a hard fault. When I track down my printf() function in disassembly code, I found it stops at here. It should be at accessing the data section.

    But both accesses are in the regions that are enabled, including their sub-regions.

    Does it mean that, when PRIVDEFENA is set 0 and MPU is enabled, the application is in unprivileged mode and it can't access to any memory space?

    Thanks!

    Crane

  • Hi Crane,

    The result is that SPI access will still cause a hard fault. 

    You actually do not include the SPI register in your region definition.

     

    So, it is expected to trigger hardfault if you choose lin 23.

    Region 0: MPU_RBAR: 0x20200000 MPU_RASR: 0x0302001D

    You have set SRAM 32KB as a full-access region, it should work with unpriviledged mode.

    If you looks at the arm m0plus user guide:

    You set a 010b for S-C-B  with the value "0x0302001D". This doesn't follow the user guide recommendation, as below:

    By the way, for the reserved bit: [bit:19-21], MSPM0 MPU unit gives a definition for them. If you look at the "mpu_armv7.h" and "core_cm0plus.h":

    I suggest you called the library to set the access permission attributes. Maybe this is the other part which makes your SRAM access out of expectation.

    For Region 0(SRAM), I set the MPU_RASR as 0x0329001D, which generated by

    "ARM_MPU_RASR_EX(0, ARM_MPU_AP_FULL, ARM_MPU_ACCESS_NORMAL(1,1,1), 0, ARM_MPU_REGION_SIZE_32KB)"

    B.R.

    Sal

  • Hi Sal,

    Obviously I ignored the actual RAM space for UART0 and SPI1. As long as the initialization for UART0 is added, the hard fault caused by calling my own printf() is gone. 

    Region 0: MPU_RBAR: 0x20200000 MPU_RASR: 0x0302C01D
    Region 1: MPU_RBAR: 0x00000001 MPU_RASR: 0x0302C021
    Region 2: MPU_RBAR: 0x400A0002 MPU_RASR: 0x0301011F
    Region 3: MPU_RBAR: 0x400C0003 MPU_RASR: 0x0301001F
    Region 4: MPU_RBAR: 0x20207804 MPU_RASR: 0x03020015
    Region 5: MPU_RBAR: 0x20206005 MPU_RASR: 0x03020015
    Region 6: MPU_RBAR: 0x40108006 MPU_RASR: 0x03020019
    Region 7: MPU_RBAR: 0x00000007 MPU_RASR: 0x00000000

    But it didn't stop at accessing UART0 registers, but at clearing the array tempMsg[] as posted yesterday. No idea why yet.

    In terms of S-C-B control, I didn't make any change, and it works fine. I will keep in mind in the future to see how they affect MPU control.

    Thanks a lot for your help!

    Regards,

    Crane