I am creating an RTOS kernel using MSP432 Arm controller. I am using PendSV for context switching.
The issue is that when the systick handler sets PendSV handler but it is never called. I have the Systick handler at priority 0 and PendSV at priority 15. I am not sure what is going wrong but I have tried to minimize the program but this has not help. Any advice would help, thank you.
void SysTick_Handler(void) {
OS_tick();
__disable_interrupts(); // #suppress("Function cannot be resolved")
OS_sched();
__enable_interrupts(); // #suppress("Function cannot be resolved")
}
void OS_init(void *stkSto, uint32_t stkSize){
// set the penSV interrupt priority to the lowest level
NVIC_SetPriority( PendSV_IRQn, 0xFF) ; // #suppress("Invalid arguments")
OSThread_start(&idleThread,
&main_idleThread,
stkSto,stkSize);
}
void OS_sched(void){
if(OS_readySet == 0U){ // idle condition
OS_currIdx = 0U; // set oscurridc to idle thread
}
else{
// if else we have threads to run need ot do in round robin
do{
++OS_currIdx;
if(OS_currIdx == OS_ThreadNum){
OS_currIdx = 1U;
}
} while((OS_readySet & (1U << (OS_currIdx - 1U))) == 0U);
}
OS_next = OS_thread[OS_currIdx];
if(OS_next != OS_curr){
// Pend a PendSV exception using by writing 1 to PENDSVSET at bit 28
*(uint32_t volatile *)0xE000ED04 = (0x1 << 28);
}
}
void PendSV_Handler(void)
{
PendSV_HandlerAsm();
}
Related
I am facing a strange issue while programming PIC18f45k22. I am initiating system modules and then I write a blocking delay for 3 seconds to wait for a touch screen to start (because I need to send some information to this screen). But when I do this I discovered that when I initiate timer before writing the delay, I discover that the system freezes.
This is the code that I used
NOTE: all the functions work fine without any problem.
void main(void) {
Sys_Init();
__delay_ms(3000);
while(1){
//Code
}
System initiation code
void Sys_Init(void) {
Delay_XTAL();
OSCILLATOR_Init();
DIGITAL_PIN_STATE();
ANALOG_PIN_STATE();
ADC_INIT(); //change clock select pins when oscillator changes
Spi_Init();
DHT22_init();
Uart_Init(9600); //initiate UART (change baud values when oscillator value changed)
Timer1_Init(); //initiate timer one (change prescaler and counter value if oscillator value changes)
}
Timer code
void Timer1_Init(void){ //for interrupt program use this function
//Prescaler 1:1; TMR1 Preload = 61536; Actual Interrupt Time : 1 ms
T1CON = 0x01;
TMR1IF = 0;
TMR1H = 0xF0;
TMR1L = 0x60;
TMR1IE = 1;
INTCON = 0xC0;
}
Interrupt code
void __interrupt() ISR (void){
Timer1();
}
void Timer1(void){ //for interrupt program
if (TMR1IF){
cnt1++;
TMR1H = 0xF0; //overflow every 1 ms
TMR1L = 0x60;
TMR1IF = 0;
}
}
#include "stm32f30x_conf.h"
uint16_t read_pos(void);
void PC_Conf(void);
uint8_t get_bit(uint8_t, uint8_t);
// PROCESSORTACT = 64 MHz
// AHB Prescaler = 1
// APB1 Prescaler = 2
// APB2 Prescaler = 1
long pin = 1;
long dir = 1;
char recvd;
int main(void){
/*
*/
//Definitions
GPIO_InitTypeDef GPIO_Initstructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_NVICInitStructure;
//ENABLE CLOCK
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//GPIO
GPIO_Initstructure.GPIO_Mode=GPIO_Mode_OUT;
GPIO_Initstructure.GPIO_OType=GPIO_OType_PP;
GPIO_Initstructure.GPIO_Pin=GPIO_Pin_All;
GPIO_Initstructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_Initstructure);
//TIMER
TIM_TimeBaseInitStructure.TIM_Prescaler = (64000-1); //TIM2 cycle to 1kHz
TIM_TimeBaseInitStructure.TIM_Period = 500; //Every 500ms
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//NVIC
NVIC_NVICInitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_NVICInitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_NVICInitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_NVICInitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_NVICInitStructure);
//Enable everything
TIM_Cmd(TIM2, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
/* Infinite loop */
while (1)
{
}
}
void TIM2_IRQHandler(void)
{
GPIOB->ODR &= 0;
GPIOB->ODR ^=1<<pin;
//Pin to new value
if(dir == 1)
{
if(pin == 5)
pin=11;
else if(pin == 15)
{ pin-=1;
dir = 0;
}
else
pin+=1;
}
else
{
if(pin == 11)
pin = 5;
else if(pin == 1)
{
pin+=1;
dir = 1;
}
else
pin-=1;
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
I have trouble understanding this code. First part is okay, but I don't understand the last function.
Can someone explain me simply what is going on in the last part of this code in TIM2_IRQHandler(void)?
I am new in this, any help would be welcome.
In many interrupts you need to clear the interrupt pending flag. If you don't when you exit from the handler, the interrupt will be called again. Every interrupt is described in the Reference manual of your micro. For example SPI interrupt pending flag is cleared by writing or reading from the DR register. Another one requires that bit to be cleared by the programmer.
The rule of thumb: clear the flag as soon as you enter the interrupt.
If the interrupt can be triggered by more than one event, the programmer should check which one was the source of the exception.
Hi I write code below for initial External Interrupt for LPC2138 in KEIL 4.7 Compiler and when run code in proteus software , code dosent Work. I double check VIC and EXTINT registers seems correct. thanks
Project Picture on Proteus
one Switch on EXTINT2 (P0.15) and one LED on P1.25
#include <LPC213x.h>
void delay(int count);
void init_ext_interrupt(void);
__irq void Ext_ISR(void);
int main (void)
{
init_ext_interrupt(); // initialize the external interrupt
while (1)
{
}
}
void init_ext_interrupt(void) //Initialize Interrupt
{
EXTMODE = (1<<2); //Edge sensitive mode on EINT2
EXTPOLAR &= ~(1<<2); //Falling Edge Sensitive
PINSEL0 = 0x80000000; //Select Pin function P0.15 as EINT2
/* initialize the interrupt vector */
VICIntSelect &= ~(1<<16); // EINT2 selected as IRQ 16
VICVectAddr5 = (unsigned)Ext_ISR; // address of the ISR
VICVectCntl5 = (1<<5) | 16;
VICIntEnable = (1<<16); // EINT2 interrupt enabled
EXTINT &= ~(1<<2); //Set interrupt
}
__irq void Ext_ISR(void) // Interrupt Service Routine-ISR
{
IO1DIR |= (1<<25);
IO1SET |= (1<<25); // Turn ON LED
delay(100000);
IO1CLR |= (1<<25); // Turn OFF LED
EXTINT |= (1<<2); //clear interrupt
VICVectAddr = 0; // End of interrupt execution
}
void delay(int count)
{
int j=0,i=0;
for(j=0;j<count;j++)
{
for(i=0;i<35;i++);
}
}
You should correct the line:
(VICVectCntl5 = (1<<5) | 16;)
to:
(VICVectCntl5 = 0x20 | 16;)
as datasheet said.
I've been doing a project about home automation in which I have to use timer interrupts with 8051 microcontroller. I've constructed the following code, however I couldn't manage to get interrupt working. It seems that the program does not go into timer ISR at all. I use a buton to simulate PIR input, therefore lampControl is triggered, no worries there. I use as a library.
Any ideas or help will be greately appreciated:
void timer0_isr(void) interrupt 1 //Timer 0 Interrupt
{
TH0 = 0xDC;
TL0 = 0x00;
TR0 = 1;
if (++lamp_interrupt_count == 6000)
{
sendCharacterShowAsHex(0x8F);
lamp_interrupt_count = 0;
TR0 = 0;
}
}
void main()
{
unsigned char chr;
IE = 0x93;
while(1)
{
serialInput();
if (getPIRInput() == 0x00)
{
lampControl(0x80);
}
....
....
....
}
void lampControl(unsigned char serial_data_in)
{
if (serial_data_in == 0x80)
{
sendCharacterShowAsHex(0x80);
//enable interrupts
IE = 0x93;
device_interrupt = 2; //Lamp
TMOD = 0x21; // Timer0 Gate=0, Mode 1, 16bit timer
TH0 = 0xDC;
TL0 = 0x00;
TR0 = 1;
}
else if(serial_data_in == 0x8F)
{
sendCharacterShowAsHex(0x8F);
}
}
You need to configure the timer and interrupts before you can use them.
In main() you need at least the following configuration bits set in order to be able to turn
the timer on with "TR0 = 1;" :
Set those bits first thing in main() and this should do the trick:
TMOD = 0x01; // 16-bit no auto reload
TH0 = 0xDC; //Set high and low bits to count 0xFFFF - 0xDC00 = 0x23FF counts
TL0 = 0x00;
ET0 = 1; // Enable timer0 interrupt
EA = 1; // Enable all interrupts
//TR0 = 1; //Enable Timer0 immediately
The rest of your code should run fine.
Note: you could change your interrupt function definition to:
"void timer0_isr(void) interrupt 1 using 1" to force it to use register bank 1 for the interrupt function operation.
For last 2 weeks am trying to learn timer & interrupt & wrote a program (with my understanding) to blink LEDs on ATMEGA2560 but no matter what I do TCNT0 never increments & ISR() function never gets called. Where am I going wrong and how can I fix it? Here is my code:
#include<avr/io.h>
#include<avr/interrupt.h>
#define READ_ATMEGA(ADDR) *((P_CHAR)(BASE_ADDR + ((ADDR) * ADDR_MULTIPLIER)))
#define WRITE_ATMEGA(ADDR, DATA) *((P_CHAR)(BASE_ADDR + ((ADDR) * ADDR_MULTIPLIER))) = DATA
#define BASE_ADDR 0x20
void init_timer0_ovf_interrupt(void);
void timer0_interrupt_isr(void);
void initialize_ports(void);
void delay(unsigned int no_65_5ms_interrupts);
void __attribute__((ISR)) timer0_interrupt_isr(void);
//#pragma interrupt_handler timer0_interrupt_isr:24
unsigned int delay_timer;
int main(void)
{
initialize_ports();
init_timer0_ovf_interrupt();
delay(46);
return 0;
}
void initialize_ports(void)
{
READ_ATMEGA(4) = 0xff;
WRITE_ATMEGA(5, 0x00);
}
void delay(unsigned int no_65_5ms_interrupts)
{
TCNT0 = 0x00;
delay_timer = 0;
while(delay_timer <= no_65_5ms_interrupts)
{
;
}
}
void init_timer0_ovf_interrupt(void)
{
TCCR0A = 0X00;
TCCR0B = 0x02;
TIMSK0 = 0x01;
TIFR0 = 1<<0;
OCR0A = 25;
sei();
}
void timer0_interrupt_isr(void)
{
delay_timer++;
if(delay_timer >= OCR0A)
{
PORTB = ~(PORTB);
delay_timer = 0;
}
}
The global variable delay_timer is shared between interrupt and non-interrupt code. It should be declared as volatile as the value can change outside of delay().
If you look at the generated code for delay() you'll probably see that the value of delay_timer isn't being re-read while spinning in the while loop.
Also, volatile isn't enough. You've got non-interrupt code and interrupt code both writing to the same variable (delay_timer). You need to protect writes to the variable in non-interrupt code, there's a race-condition there. The easy/lazy way is to disable interrupts & restore them in the non-interrupt code.
(As for setting up your interrupts & starting your timer, that info should be in the chip's datasheet. Usually that's the part that's easier to get right, it's the shared data stuff that bites people.)
3-4 days ago, I wrote the same program a little differently & got LEDs blinking but still not sure whether it is the correct way of using timer & interrupt. Could anyone please see this & tell me whether it's the correct or not? I managed to write this program by reading programs of timers, interrupts.
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t intrs;
ISR(TIMER0_OVF_vect) {
/* this ISR is called when TIMER0 overflows */
intrs++;
/* strobe PORTB.5 - the LED on arduino boards */
if (intrs >= 61){
PORTB = ~PORTB;
intrs = 0;
}
}
int main(void) {
TCCR0B = 0x02;
/* Enable Timer Overflow Interrupts */
TIMSK0 = 0x01;
/* other set up */
DDRB = 0xff;
TCNT0 = 0;
intrs = 0;
/* Enable Interrupts */
sei();
while (1)
; /* empty loop */
}
If it's the correct way then I can start working on next step.
Thanks
If could be that your while loop in the delay function doesn't do anything and will not increment delay_timer so you are stuck in an endless loop:
void delay(unsigned int no_65_5ms_interrupts)
{
TCNT0 = 0x00;
delay_timer = 0;
while(delay_timer <= no_65_5ms_interrupts)
{
; //Nothing is happening here!!
}
}