/* --COPYRIGHT--,BSD * Copyright (c) 2014, 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. * --/COPYRIGHT--*/ //***************************************************************************** // // mpu.c - Driver for the mpu Module. // //***************************************************************************** //***************************************************************************** // //! \addtogroup mpu_api mpu //! @{ // //***************************************************************************** #include "inc/hw_regaccess.h" #include "inc/hw_memmap.h" #ifdef __MSP430_HAS_MPU__ #include "mpu.h" #include //***************************************************************************** // // The following value is used by createTwoSegments, createThreeSegments to // check the user has passed a valid segmentation value. This value was // obtained from the User's Guide. // //***************************************************************************** #define MPU_MAX_SEG_VALUE 0x13C1 void MPU_initTwoSegments(uint16_t baseAddress, uint16_t seg1boundary, uint8_t seg1accmask, uint8_t seg2accmask) { // Write MPU password to allow MPU register configuration HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | HWREG8( baseAddress + OFS_MPUCTL0); // Create two memory segmentations HWREG16(baseAddress + OFS_MPUSEGB1) = seg1boundary; HWREG16(baseAddress + OFS_MPUSEGB2) = seg1boundary; // Set access rights based on user's selection for segment1 switch(seg1accmask) { case MPU_EXEC | MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG1WE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG1XE + MPUSEG1RE; break; case MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG1XE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG1RE + MPUSEG1WE; break; case MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG1XE + MPUSEG1WE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG1RE; break; case MPU_EXEC | MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) |= (MPUSEG1XE + MPUSEG1WE + MPUSEG1RE); break; case MPU_NO_READ_WRITE_EXEC: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG1XE + MPUSEG1WE + MPUSEG1RE); break; default: break; } // Set access rights based on user's selection for segment2 switch(seg2accmask) { case MPU_EXEC | MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG3WE + MPUSEG2WE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG3XE + MPUSEG3RE + MPUSEG2XE + MPUSEG2RE; break; case MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG3XE + MPUSEG2XE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG3RE + MPUSEG3WE + MPUSEG2RE + MPUSEG2WE; break; case MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG3XE + MPUSEG3WE + MPUSEG2XE + MPUSEG2WE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG3RE + MPUSEG2RE; break; case MPU_EXEC | MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) |= (MPUSEG3XE + MPUSEG3WE + MPUSEG3RE + MPUSEG2XE + MPUSEG2WE + MPUSEG2RE); break; case MPU_NO_READ_WRITE_EXEC: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG3XE + MPUSEG3WE + MPUSEG3RE + MPUSEG2XE + MPUSEG2WE + MPUSEG2RE); break; default: break; } //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } void MPU_initThreeSegments(uint16_t baseAddress, MPU_initThreeSegmentsParam *param) { // Write MPU password to allow MPU register configuration HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | HWREG8( baseAddress + OFS_MPUCTL0); // Create two memory segmentations HWREG16(baseAddress + OFS_MPUSEGB1) = param->seg1boundary; HWREG16(baseAddress + OFS_MPUSEGB2) = param->seg2boundary; // Set access rights based on user's selection for segment1 switch(param->seg1accmask) { case MPU_EXEC | MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG1WE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG1XE + MPUSEG1RE; break; case MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG1XE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG1RE + MPUSEG1WE; break; case MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG1XE + MPUSEG1WE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG1RE; break; case MPU_EXEC | MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) |= (MPUSEG1XE + MPUSEG1WE + MPUSEG1RE); break; case MPU_NO_READ_WRITE_EXEC: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG1XE + MPUSEG1WE + MPUSEG1RE); break; default: break; } // Set access rights based on user's selection for segment2 switch(param->seg2accmask) { case MPU_EXEC | MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG2WE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG2XE + MPUSEG2RE; break; case MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG2XE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG2RE + MPUSEG2WE; break; case MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG2XE + MPUSEG2WE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG2RE; break; case MPU_EXEC | MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) |= (MPUSEG2XE + MPUSEG2WE + MPUSEG2RE); break; case MPU_NO_READ_WRITE_EXEC: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG2XE + MPUSEG2WE + MPUSEG2RE); break; default: break; } // Set access rights based on user's selection for segment3 switch(param->seg3accmask) { case MPU_EXEC | MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG3WE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG3XE + MPUSEG3RE; break; case MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEG3XE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG3RE + MPUSEG3WE; break; case MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG3XE + MPUSEG3WE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEG3RE; break; case MPU_EXEC | MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) |= (MPUSEG3XE + MPUSEG3WE + MPUSEG3WE); break; case MPU_NO_READ_WRITE_EXEC: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEG3XE + MPUSEG3WE + MPUSEG3WE); break; default: break; } //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } void MPU_initInfoSegment(uint16_t baseAddress, uint8_t accmask) { // Write MPU password to allow MPU register configuration HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | HWREG8( baseAddress + OFS_MPUCTL0); // Set access rights based on user's selection for segment1 switch(accmask) { case MPU_EXEC | MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEGIWE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEGIXE + MPUSEGIRE; break; case MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) &= ~MPUSEGIXE; HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEGIRE + MPUSEGIWE; break; case MPU_READ: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEGIXE + MPUSEGIWE); HWREG16(baseAddress + OFS_MPUSAM) |= MPUSEGIRE; break; case MPU_EXEC | MPU_READ | MPU_WRITE: HWREG16(baseAddress + OFS_MPUSAM) |= (MPUSEGIXE + MPUSEGIWE + MPUSEGIRE); break; case MPU_NO_READ_WRITE_EXEC: HWREG16(baseAddress + OFS_MPUSAM) &= ~(MPUSEGIXE + MPUSEGIWE + MPUSEGIRE); break; default: break; } //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } void MPU_enableNMIevent(uint16_t baseAddress) { HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | MPUSEGIE | HWREG8(baseAddress + OFS_MPUCTL0); //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } void MPU_start(uint16_t baseAddress) { HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | MPUENA | HWREG8( baseAddress + OFS_MPUCTL0); //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } void MPU_enablePUCOnViolation(uint16_t baseAddress, uint16_t segment) { HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | HWREG8( baseAddress + OFS_MPUCTL0); HWREG16(baseAddress + OFS_MPUSAM) |= segment; //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } void MPU_disablePUCOnViolation(uint16_t baseAddress, uint16_t segment) { HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | HWREG8( baseAddress + OFS_MPUCTL0); HWREG16(baseAddress + OFS_MPUSAM) &= ~segment; //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } uint16_t MPU_getInterruptStatus(uint16_t baseAddress, uint16_t memAccFlag) { return (HWREG16(baseAddress + OFS_MPUCTL1) & memAccFlag); } uint16_t MPU_clearInterrupt(uint16_t baseAddress, uint16_t memAccFlag) { HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | HWREG8( baseAddress + OFS_MPUCTL0); HWREG16(baseAddress + OFS_MPUCTL1) &= ~memAccFlag; //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; return (HWREG16(baseAddress + OFS_MPUCTL1) & memAccFlag); } uint16_t MPU_clearAllInterrupts(uint16_t baseAddress) { HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | HWREG8( baseAddress + OFS_MPUCTL0); HWREG16(baseAddress + OFS_MPUCTL1) &= ~(MPUSEG1IFG + MPUSEG2IFG + MPUSEG3IFG); //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; return (HWREG16(baseAddress + OFS_MPUCTL1) & (MPUSEG1IFG + MPUSEG2IFG + MPUSEG3IFG)); } void MPU_lockMPU(uint16_t baseAddress) { HWREG16(baseAddress + OFS_MPUCTL0) = MPUPW | MPULOCK | HWREG8(baseAddress + OFS_MPUCTL0); //Lock MPU to disable writing to all registers HWREG8(baseAddress + OFS_MPUCTL0_H) = 0x00; } #endif //***************************************************************************** // //! Close the doxygen group for mpu_api //! @} // //*****************************************************************************