1// CMSIS abstraction functions. 2// 3// Original copyright: 4// 5// Copyright (c) 2009 - 2015 ARM LIMITED 6// 7// All rights reserved. 8// Redistribution and use in source and binary forms, with or without 9// modification, are permitted provided that the following conditions are met: 10// - Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// - Redistributions in binary form must reproduce the above copyright 13// notice, this list of conditions and the following disclaimer in the 14// documentation and/or other materials provided with the distribution. 15// - Neither the name of ARM nor the names of its contributors may be used 16// to endorse or promote products derived from this software without 17// specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22// ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 23// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29// POSSIBILITY OF SUCH DAMAGE. 30package arm 31 32import ( 33 "errors" 34 "runtime/volatile" 35 "unsafe" 36) 37 38var errCycleCountTooLarge = errors.New("requested cycle count is too large, overflows 24 bit counter") 39 40// Run the given assembly code. The code will be marked as having side effects, 41// as it doesn't produce output and thus would normally be eliminated by the 42// optimizer. 43func Asm(asm string) 44 45// Run the given inline assembly. The code will be marked as having side 46// effects, as it would otherwise be optimized away. The inline assembly string 47// recognizes template values in the form {name}, like so: 48// 49// arm.AsmFull( 50// "str {value}, {result}", 51// map[string]interface{}{ 52// "value": 1 53// "result": &dest, 54// }) 55// 56// You can use {} in the asm string (which expands to a register) to set the 57// return value. 58func AsmFull(asm string, regs map[string]interface{}) uintptr 59 60// Run the following system call (SVCall) with 0 arguments. 61func SVCall0(num uintptr) uintptr 62 63// Run the following system call (SVCall) with 1 argument. 64func SVCall1(num uintptr, a1 interface{}) uintptr 65 66// Run the following system call (SVCall) with 2 arguments. 67func SVCall2(num uintptr, a1, a2 interface{}) uintptr 68 69// Run the following system call (SVCall) with 3 arguments. 70func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr 71 72// Run the following system call (SVCall) with 4 arguments. 73func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr 74 75const ( 76 SCS_BASE = 0xE000E000 77 SYST_BASE = SCS_BASE + 0x0010 78 NVIC_BASE = SCS_BASE + 0x0100 79 SCB_BASE = SCS_BASE + 0x0D00 80) 81 82const ( 83 SCB_AIRCR_VECTKEY_Pos = 16 84 SCB_AIRCR_SYSRESETREQ_Pos = 2 85 SCB_AIRCR_SYSRESETREQ_Msk = 1 << SCB_AIRCR_SYSRESETREQ_Pos 86) 87 88// System Control Block (SCB) 89// 90// SCB_Type provides the definitions for the System Control Block Registers. 91type SCB_Type struct { 92 CPUID volatile.Register32 // CPUID Base Register 93 ICSR volatile.Register32 // Interrupt Control and State Register 94 VTOR volatile.Register32 // Vector Table Offset Register 95 AIRCR volatile.Register32 // Application Interrupt and Reset Control Register 96 SCR volatile.Register32 // System Control Register 97 CCR volatile.Register32 // Configuration Control Register 98 _ volatile.Register32 // RESERVED1; 99 SHP [2]volatile.Register32 // System Handlers Priority Registers. [0] is RESERVED 100 SHCSR volatile.Register32 // System Handler Control and State Register 101} 102 103var SCB = (*SCB_Type)(unsafe.Pointer(uintptr(SCB_BASE))) 104 105// Nested Vectored Interrupt Controller (NVIC). 106// 107// Source: 108// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CIHIGCIF.html 109type NVIC_Type struct { 110 ISER [8]volatile.Register32 // Interrupt Set-enable Registers 111 _ [24]uint32 112 ICER [8]volatile.Register32 // Interrupt Clear-enable Registers 113 _ [24]uint32 114 ISPR [8]volatile.Register32 // Interrupt Set-pending Registers 115 _ [24]uint32 116 ICPR [8]volatile.Register32 // Interrupt Clear-pending Registers 117 _ [24]uint32 118 IABR [8]volatile.Register32 // Interrupt Active Bit Registers 119 _ [56]uint32 120 IPR [60]volatile.Register32 // Interrupt Priority Registers 121} 122 123var NVIC = (*NVIC_Type)(unsafe.Pointer(uintptr(NVIC_BASE))) 124 125// System Timer (SYST) 126// 127// Source: https://static.docs.arm.com/ddi0403/e/DDI0403E_d_armv7m_arm.pdf B3.3 128type SYST_Type struct { 129 SYST_CSR volatile.Register32 130 SYST_RVR volatile.Register32 131 SYST_CVR volatile.Register32 132 SYST_CALIB volatile.Register32 133} 134 135var SYST = (*SYST_Type)(unsafe.Pointer(uintptr(SYST_BASE))) 136 137// Bitfields for SYST: System Timer 138const ( 139 // SYST.SYST_CSR: SysTick Control and Status Register 140 SYST_CSR_ENABLE_Pos = 0x0 // Position of ENABLE field. 141 SYST_CSR_ENABLE_Msk = 0x1 // Bit mask of ENABLE field. 142 SYST_CSR_ENABLE = 0x1 // Bit ENABLE. 143 SYST_CSR_TICKINT_Pos = 0x1 // Position of TICKINT field. 144 SYST_CSR_TICKINT_Msk = 0x2 // Bit mask of TICKINT field. 145 SYST_CSR_TICKINT = 0x2 // Bit TICKINT. 146 SYST_CSR_CLKSOURCE_Pos = 0x2 // Position of CLKSOURCE field. 147 SYST_CSR_CLKSOURCE_Msk = 0x4 // Bit mask of CLKSOURCE field. 148 SYST_CSR_CLKSOURCE = 0x4 // Bit CLKSOURCE. 149 SYST_CSR_COUNTFLAG_Pos = 0x10 // Position of COUNTFLAG field. 150 SYST_CSR_COUNTFLAG_Msk = 0x10000 // Bit mask of COUNTFLAG field. 151 SYST_CSR_COUNTFLAG = 0x10000 // Bit COUNTFLAG. 152 153 // SYST.SYST_RVR: SysTick Reload Value Register 154 SYST_RVR_RELOAD_Pos = 0x0 // Position of RELOAD field. 155 SYST_RVR_RELOAD_Msk = 0xffffff // Bit mask of RELOAD field. 156 157 // SYST.SYST_CVR: SysTick Current Value Register 158 SYST_CVR_CURRENT_Pos = 0x0 // Position of CURRENT field. 159 SYST_CVR_CURRENT_Msk = 0xffffff // Bit mask of CURRENT field. 160 161 // SYST.SYST_CALIB: SysTick Calibration Value Register 162 SYST_CALIB_TENMS_Pos = 0x0 // Position of TENMS field. 163 SYST_CALIB_TENMS_Msk = 0xffffff // Bit mask of TENMS field. 164 SYST_CALIB_SKEW_Pos = 0x1e // Position of SKEW field. 165 SYST_CALIB_SKEW_Msk = 0x40000000 // Bit mask of SKEW field. 166 SYST_CALIB_SKEW = 0x40000000 // Bit SKEW. 167 SYST_CALIB_NOREF_Pos = 0x1f // Position of NOREF field. 168 SYST_CALIB_NOREF_Msk = 0x80000000 // Bit mask of NOREF field. 169 SYST_CALIB_NOREF = 0x80000000 // Bit NOREF. 170) 171 172// Enable the given interrupt number. 173func EnableIRQ(irq uint32) { 174 NVIC.ISER[irq>>5].Set(1 << (irq & 0x1F)) 175} 176 177// Disable the given interrupt number. 178func DisableIRQ(irq uint32) { 179 NVIC.ICER[irq>>5].Set(1 << (irq & 0x1F)) 180} 181 182// Set the priority of the given interrupt number. 183// Note that the priority is given as a 0-255 number, where some of the lower 184// bits are not implemented by the hardware. For example, to set a low interrupt 185// priority, use 0xc0, which is equivalent to using priority level 5 when the 186// hardware has 8 priority levels. Also note that the priority level is inverted 187// in ARM: a lower number means it is a more important interrupt and will 188// interrupt ISRs with a higher interrupt priority. 189func SetPriority(irq uint32, priority uint32) { 190 // Details: 191 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/Cihgjeed.html 192 regnum := irq / 4 193 regpos := irq % 4 194 mask := uint32(0xff) << (regpos * 8) // bits to clear 195 priority = priority << (regpos * 8) // bits to set 196 NVIC.IPR[regnum].Set((uint32(NVIC.IPR[regnum].Get()) &^ mask) | priority) 197} 198 199// DisableInterrupts disables all interrupts, and returns the old interrupt 200// state. 201func DisableInterrupts() uintptr { 202 return AsmFull(` 203 mrs {}, PRIMASK 204 cpsid i 205 `, nil) 206} 207 208// EnableInterrupts enables all interrupts again. The value passed in must be 209// the mask returned by DisableInterrupts. 210func EnableInterrupts(mask uintptr) { 211 AsmFull("msr PRIMASK, {mask}", map[string]interface{}{ 212 "mask": mask, 213 }) 214} 215 216// SystemReset performs a hard system reset. 217func SystemReset() { 218 // SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | 219 // SCB_AIRCR_SYSRESETREQ_Msk); 220 SCB.AIRCR.Set((0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk) 221 222 for { 223 Asm("wfi") 224 } 225} 226 227// Set up the system timer to generate periodic tick events. 228// This will cause SysTick_Handler to fire once per tick. 229// The cyclecount parameter is a counter value which can range from 0 to 230// 0xffffff. A value of 0 disables the timer. 231func SetupSystemTimer(cyclecount uint32) error { 232 // turn it off 233 SYST.SYST_CSR.ClearBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE) 234 if cyclecount == 0 { 235 // leave the system timer turned off. 236 return nil 237 } 238 if cyclecount&SYST_RVR_RELOAD_Msk != cyclecount { 239 // The cycle refresh register is only 24 bits wide. The user-specified value will overflow. 240 return errCycleCountTooLarge 241 } 242 243 // set refresh count 244 SYST.SYST_RVR.Set(cyclecount) 245 // set current counter value 246 SYST.SYST_CVR.Set(cyclecount) 247 // enable clock, enable SysTick interrupt when clock reaches 0, run it off of the processor clock 248 SYST.SYST_CSR.SetBits(SYST_CSR_TICKINT | SYST_CSR_ENABLE | SYST_CSR_CLKSOURCE) 249 return nil 250} 251