// CMSIS abstraction functions. // // Original copyright: // // Copyright (c) 2009 - 2015 ARM LIMITED // // 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 ARM 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 COPYRIGHT HOLDERS AND 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. package arm import ( "errors" "runtime/volatile" "unsafe" ) var errCycleCountTooLarge = errors.New("requested cycle count is too large, overflows 24 bit counter") // Run the given assembly code. The code will be marked as having side effects, // as it doesn't produce output and thus would normally be eliminated by the // optimizer. func Asm(asm string) // Run the given inline assembly. The code will be marked as having side // effects, as it would otherwise be optimized away. The inline assembly string // recognizes template values in the form {name}, like so: // // arm.AsmFull( // "str {value}, {result}", // map[string]interface{}{ // "value": 1 // "result": &dest, // }) // // You can use {} in the asm string (which expands to a register) to set the // return value. func AsmFull(asm string, regs map[string]interface{}) uintptr // Run the following system call (SVCall) with 0 arguments. func SVCall0(num uintptr) uintptr // Run the following system call (SVCall) with 1 argument. func SVCall1(num uintptr, a1 interface{}) uintptr // Run the following system call (SVCall) with 2 arguments. func SVCall2(num uintptr, a1, a2 interface{}) uintptr // Run the following system call (SVCall) with 3 arguments. func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr // Run the following system call (SVCall) with 4 arguments. func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr const ( SCS_BASE = 0xE000E000 SYST_BASE = SCS_BASE + 0x0010 NVIC_BASE = SCS_BASE + 0x0100 ) // Nested Vectored Interrupt Controller (NVIC). // // Source: // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CIHIGCIF.html type NVIC_Type struct { ISER [8]volatile.Register32 // Interrupt Set-enable Registers _ [24]uint32 ICER [8]volatile.Register32 // Interrupt Clear-enable Registers _ [24]uint32 ISPR [8]volatile.Register32 // Interrupt Set-pending Registers _ [24]uint32 ICPR [8]volatile.Register32 // Interrupt Clear-pending Registers _ [24]uint32 IABR [8]volatile.Register32 // Interrupt Active Bit Registers _ [56]uint32 IPR [60]volatile.Register32 // Interrupt Priority Registers } var NVIC = (*NVIC_Type)(unsafe.Pointer(uintptr(NVIC_BASE))) // System Timer (SYST) // // Source: https://static.docs.arm.com/ddi0403/e/DDI0403E_d_armv7m_arm.pdf B3.3 type SYST_Type struct { SYST_CSR volatile.Register32 SYST_RVR volatile.Register32 SYST_CVR volatile.Register32 SYST_CALIB volatile.Register32 } var SYST = (*SYST_Type)(unsafe.Pointer(uintptr(SYST_BASE))) // Bitfields for SYST: System Timer const ( // SYST.SYST_CSR: SysTick Control and Status Register SYST_CSR_ENABLE_Pos = 0x0 // Position of ENABLE field. SYST_CSR_ENABLE_Msk = 0x1 // Bit mask of ENABLE field. SYST_CSR_ENABLE = 0x1 // Bit ENABLE. SYST_CSR_TICKINT_Pos = 0x1 // Position of TICKINT field. SYST_CSR_TICKINT_Msk = 0x2 // Bit mask of TICKINT field. SYST_CSR_TICKINT = 0x2 // Bit TICKINT. SYST_CSR_CLKSOURCE_Pos = 0x2 // Position of CLKSOURCE field. SYST_CSR_CLKSOURCE_Msk = 0x4 // Bit mask of CLKSOURCE field. SYST_CSR_CLKSOURCE = 0x4 // Bit CLKSOURCE. SYST_CSR_COUNTFLAG_Pos = 0x10 // Position of COUNTFLAG field. SYST_CSR_COUNTFLAG_Msk = 0x10000 // Bit mask of COUNTFLAG field. SYST_CSR_COUNTFLAG = 0x10000 // Bit COUNTFLAG. // SYST.SYST_RVR: SysTick Reload Value Register SYST_RVR_RELOAD_Pos = 0x0 // Position of RELOAD field. SYST_RVR_RELOAD_Msk = 0xffffff // Bit mask of RELOAD field. // SYST.SYST_CVR: SysTick Current Value Register SYST_CVR_CURRENT_Pos = 0x0 // Position of CURRENT field. SYST_CVR_CURRENT_Msk = 0xffffff // Bit mask of CURRENT field. // SYST.SYST_CALIB: SysTick Calibration Value Register SYST_CALIB_TENMS_Pos = 0x0 // Position of TENMS field. SYST_CALIB_TENMS_Msk = 0xffffff // Bit mask of TENMS field. SYST_CALIB_SKEW_Pos = 0x1e // Position of SKEW field. SYST_CALIB_SKEW_Msk = 0x40000000 // Bit mask of SKEW field. SYST_CALIB_SKEW = 0x40000000 // Bit SKEW. SYST_CALIB_NOREF_Pos = 0x1f // Position of NOREF field. SYST_CALIB_NOREF_Msk = 0x80000000 // Bit mask of NOREF field. SYST_CALIB_NOREF = 0x80000000 // Bit NOREF. ) // Enable the given interrupt number. func EnableIRQ(irq uint32) { NVIC.ISER[irq>>5].Set(1 << (irq & 0x1F)) } // Disable the given interrupt number. func DisableIRQ(irq uint32) { NVIC.ICER[irq>>5].Set(1 << (irq & 0x1F)) } // Set the priority of the given interrupt number. // Note that the priority is given as a 0-255 number, where some of the lower // bits are not implemented by the hardware. For example, to set a low interrupt // priority, use 0xc0, which is equivalent to using priority level 5 when the // hardware has 8 priority levels. Also note that the priority level is inverted // in ARM: a lower number means it is a more important interrupt and will // interrupt ISRs with a higher interrupt priority. func SetPriority(irq uint32, priority uint32) { // Details: // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/Cihgjeed.html regnum := irq / 4 regpos := irq % 4 mask := uint32(0xff) << (regpos * 8) // bits to clear priority = priority << (regpos * 8) // bits to set NVIC.IPR[regnum].Set((uint32(NVIC.IPR[regnum].Get()) &^ mask) | priority) } // DisableInterrupts disables all interrupts, and returns the old interrupt // state. func DisableInterrupts() uintptr { return AsmFull(` mrs {}, PRIMASK cpsid i `, nil) } // EnableInterrupts enables all interrupts again. The value passed in must be // the mask returned by DisableInterrupts. func EnableInterrupts(mask uintptr) { AsmFull("msr PRIMASK, {mask}", map[string]interface{}{ "mask": mask, }) } // Set up the system timer to generate periodic tick events. // This will cause SysTick_Handler to fire once per tick. // The cyclecount parameter is a counter value which can range from 0 to // 0xffffff. A value of 0 disables the timer. func SetupSystemTimer(cyclecount uint32) error { // turn it off SYST.SYST_CSR.ClearBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE) if cyclecount == 0 { // leave the system timer turned off. return nil } if cyclecount&SYST_RVR_RELOAD_Msk != cyclecount { // The cycle refresh register is only 24 bits wide. The user-specified value will overflow. return errCycleCountTooLarge } // set refresh count SYST.SYST_RVR.Set(cyclecount) // set current counter value SYST.SYST_CVR.Set(cyclecount) // enable clock, enable SysTick interrupt when clock reaches 0, run it off of the processor clock SYST.SYST_CSR.SetBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE | SYST_CSR_CLKSOURCE) return nil }