I opened a new NoRTOS CCS project and modified as follows for using periodic systick interrupt:
STCSR Register -> bit0 defined as 0 // Systick disabled
STRVR Register -> RELOAD value defined // 24MHz clock every step is 41.6ns
NVIC_IPR3 Register -> bit24 priority is defined for Systick
STCSR Register -> bit0, bit1, bit2 are set //Systick enabled
with this modification when the Current value of Systick is 0, COUNTFLAG(16th bit of STCSR Register) gets set as should be.
My problem is defining Systick handler.
There is no startup.s file in the project folder. So I can not find the vector table.
Where is the vector table is defined in CCS projects?
Any help will be appreciated.
Best Kind Regards,
Related
In ri5cy documentation, it says that :
[§12.1 Interrupts] Interrupts can only be enabled/disabled on a global basis and not individually. It is assumed that there is an
event/interrupt controller outside of the core that performs masking and buffering of the interrupt lines. The global
interrupt enable is done via the CSR register MSTATUS.
but actually, there is nothing in the MSTATUS register § about this, the only thing close is:
[§MSTATUS.MIE] "Machine Interrupt Enable: If you want to enable interrupt handling in your exception handler, set the Interrupt Enable MIE to 1’b1 inside your handler code"
ok, you can enable interrupt in your exception handler but how to enable/disable globally interrupts?
Setting/Clearing MSTATUS.MIE does not en/disable globally interrupts (IRQ are always on, even if MSTATUS.MIE = 0)
So I think there is an error in the ri5cy implementation of the riscv specs,
for instance, for cv32e40x, globally interrupts en/disable is done - at core level - through the MIE CSR, so when MIE = 0xFFFFFFFF all irqs are enabled and when MIE = 0 are irqs are disabled.
Could I disable irqs globally with ri5y?
I thought about using the event controller:
to disable: saving the IER and setting it to 0
to re-enable: setting back the IER to the previous saved value
but this very looks like tinkering...
I'm working with the STM32L432KC and am relatively new to the embedded world. What happens if I write to a configuration register, wait some time, and then write to the register again with the same configuration. Does this have any effects?
For reference, I am using the STM32L432KC microcontroller. The register in question is the Reset and Clock Control (RCC), AHB2 Peripheral Clock Enable Register (RCC_AHB2ENR). I have a function that enables the clock for a GPIO port, by OR'ing in a bit. I am wondering if calling the function while the pin is active will have any effects.
There is no generic answer for all registers on all devices. The only correct course is to consult the data sheet or reference manual for the part concerned.
In the specific case of STM32L432 RCC_AHB2ENR all used bits are specified as "set and cleared by software" with no specific hardware action on read/write. This is true I believe for the RCC_AHB2ENR on all STM32. Note however that the unused bits are reserved and should not be set to any value other then the reset value - also defined in the reference manual and in this case all zero.
Some registers change value under hardware control, so re-writing a previously written value may have an effect. A simple example on your part is TIM1_CNT where if TIM1 is running the counter will have changed and rewriting it will effect its period and any capture/compare events or event output or PWM it may be used for.
Is there any way to disable all irq from Cortex M3 MCU except one ?
My issue is that I have a system running several kinds of irq with various priority levels and I want to disable all irq except one in a particular state.
I know I can disable all irq by using "__disable_irq()" instruction but I can't enable one irq after calling this instruction if I didn't call "__enable_irq()" before.
Thanks for your help,
Regards
Use the BASEPRI register to disable all interrupts below the specified priority level.
This is a core register, described in the Cortex-M3 Programming Manual.
CMSIS provides the __get_BASEPRI() and __set_BASEPRI() functions to manipulate its value.
Note that bits 7-4 are used, the priority value must be shifted left by 4. To disable all interrupts with priority 1 or lower, use
__set_BASEPRI(1 << 4);
and to enable all, set it to 0
__set_BASEPRI(0);
You should of course set interrupt priorities accordingly, ensuring that no other interrupt has priority 0.
Other than by disabling all the enabled interrupts you don't want, no.
__disable_irq() is implemented as CPSID I, which turns off all exceptions which can have a priority set (those configured in the NVIC), it achieves this by changing the PRIMASK register (setting bit 0) within the CPU. There is no way to tell this to only enable a specific interrupt.
I'm developing software for an NXP LPC1788 microcontroller, and I'm using the embOS RTOS. Whenever a message is received over USB, I want to use the OS_PutMailCond() function to store the USB message in a mailbox which a handler function is waiting on. In other words, I want to make message handling interrupt-driven.
The embOS user manual can be found here. Page 145 describes the OS_PutMailCond() function.
Whenever a USB message is received, it triggers the USB interrupt service routine on the LPC, but to let embOS know that it's an ISR I have to place OS_EnterInterrupt() and OS_LeaveInterrupt() at the start and end of the ISR respectively. This is necessary if I want to call embOS functions within it, including OS_PutMailCond().
The problem is that if I put OS_EnterInterrupt()/OS_LeaveInterrupt() anywhere within the USB ISR, the USB stops functioning properly and Windows informs me that the device has malfunctioned.
I have no idea why this is the case. We've tried something similar for handling messages over CAN, as shown below, and it works fine.
void CAN_IRQHandler(void)
{
OS_EnterInterrupt();
...
if (MBfieldCANframeInitialised)
OS_PutMailCond (&MBfieldCANframe, &recMessage);
OS_LeaveInterrupt();
}
OS_EnterInterrupt() and OS_LeaveInterrupt() are described on pages 252 and 253 of the linked manual. From the additional information section of the former:
If OS_EnterInterrupt() is used, it should be the first function to be
called in the interrupt handler. It must be used with
OS_LeaveInterrupt() as the last function called. The use of this
function has the following effects, it:
disables task switches
keeps interrupts in internal routines disabled
EDIT
I've investigated further and found out that using OS_EnterInterrupt() and OS_LeaveInterrupt() within the USB ISR (and other ISR's like the one for the GPIO when a rising or falling edge is detected on a pin) causes an OS error. The error value is 166, which means "OS-function called from ISR with high priority".
I'll update if I find out anything else.
Problem solved. It turns out the guy that made this work for the CAN ISR changed the code of one of the embOS source files to set the CAN ISR priority level from 0 to 29 (higher level = lower priority). I did the same thing for the USB ISR:
void OS_InitHW(void) {
OS_IncDI();
//
// We assume, the PLL and core clock was already set by the SystemInit() function
// which was called from the startup code
// Therefore, we don't have to initailize any hardware here,
// we just ensure that the system clock variable is updated and then
// set the periodic system timer tick for embOS.
//
SystemCoreClockUpdate(); // Update the system clock variable (might not have been set before)
if (SysTick_Config (OS_PCLK_TIMER / OS_TICK_FREQ)) { // Setup SysTick Timer for 1 msec interrupts
while (1); // Handle Error
}
//
// Initialize NVIC vector base address. Might be necessary for RAM targets or application not running from 0
//
NVIC_VTOR = (OS_U32)&__Vectors;
//
// Set the interrupt priority for the system timer to 2nd lowest level to ensure the timer can preempt PendSV handler
//
NVIC_SetPriority(SysTick_IRQn, (1u << __NVIC_PRIO_BITS) - 2u);
NVIC_SetPriority(CANActivity_IRQn, (1u << __NVIC_PRIO_BITS) - 3u);
NVIC_SetPriority(CAN_IRQn, (1u << __NVIC_PRIO_BITS) - 3u);
NVIC_SetPriority(USB_IRQn, (1u << __NVIC_PRIO_BITS) - 3u);
OS_COM_INIT();
OS_DecRI();
}
I found this in the embOS documentation:
Why can a high priority ISR not use the OS API ?
embOS disables low priority interrupts when embOS data structures are modified. During this time high priority ISR are enabled. If they would call an embOS function, which also modifies embOS data, the embOS data structures would be corrupted.
how to enable external interrupt of 8051?
Each of the 8051s interrupts has its own bit in the interrupt enable (IE) special function register (SFR) and is enabled by setting the corresponding bit. The code examples below are in 8051 assembly as well as C to provide a general idea of what is taking place.
To enable external interrupt 0 (EX0) you need to set bit 0 of IE.
SETB EX0 or ORL IE,#01 or MOV IE,#01
To enable external interrupt 1 (EX1) you need to set bit 3 of IE.
SETB EX1 or ORL IE,#08 or MOV IE,#08
Interrupts then need to be globally enabled by setting bit 7 of IE, which is the global interupt enable/disable bit (EA). If necessary, you can set the priority of the external interrupts to high via the interrupt priority (IP) SFR.
SETB EA or ORL IE,#80
Example in C:
#define IE (*(volatile unsigned char *)0xA8)
#define BIT(x) (1 << (x))
...
IE &= ~BIT(7); /* clear bit 7 of IE (EA) to disable interrupts */
...
IE |= BIT(0); /* set bit 0 of IE (EX0) to enable external interrupt 0 */
...
IE |= BIT(1); /* set bit 3 of IE (EX1) to enable external interrupt 1 */
...
IE ^= BIT(7) /* toggle bit 7 of IE (EA) to re-enable interrupts */
or
IE = 0x89; /* enable both external interrupts and globally enable interrupts */
The various 8051 C compiler vendors often define their own methods of setting up interrupt functions. You may need to consult the documentation for your specific compiler.
To define an interrupt function using the Keil C51 Compiler (pdf link to application note), an interrupt number and register bank is specified where the interrupt number corresponds to a specific interrupt vector address.
void my_external_interrupt_0_routine(void) interrupt 0 using 2
{
/* do something */
}
To define an interrupt function using the 8051 IAR C/C++ Compiler (icc8051) (pdf link to reference guide), the __interrupt keyword and the #pragma vector directive can be used.
#pragma vector=0x03
__interrupt void my_external_interrupt_0_routine(void)
{
/* do something */
}
If you are new to the 8051, there is a wealth of information available at www.8052.com. I would also recommend The 8051/8052 Microcontroller: Architecture, Assembly Language, and Hardware Interfacing written by Craig Steiner, the webmaster and author of 8052.com.
Enable the corresponding bit of external interrupt in IE register.
If it is level triggering, just write the subroutine appropriate to this interrupt, or else enable the TCON register bit corresponding to the edge triggered interrupt – whether it is INT0 or INT1.