Interrupts in MSP430F in C - c

I'm trying develop a program for the micro MSP430F1X, I'm want to simulate widescreen wipe so the idea is having 2 pin P1.0 and P1.1 as input to increase or decrease the state (been 0=stop, 1=PWM 50%, 2=PWM 75%, 3=1sec ON / 2sec OFF and repeat). At the moment I've been able to generate PWM=50%, but when I try to make a loop with a switch case routine inside the WDT interrupt it seems that it does not go into the switch I don't know why, can somebody help me please,(I'm not sure if the switch case should be implemented in the WDT interrupt or in the main function, here is my code:
#define STATE_IDLE 0
#define STATE_INTER 3
#define STATE_LOW 1
#define STATE_HIGH 2
#define WDT_MDLY_0_5 (WDTPW+WDTTMSEL+WDTCNTCL+WDTIS1)
int cnt=0; // global variable to count timer ticks
static int speed=0;
void main(void) {
// WDTCTL = WDTPW + WDTHOLD; //stop watchdog timer
WDTCTL = WDT_MDLY_0_5;
IE1 |= WDTIE;
_EINT();
P1DIR &= ~(BIT0+BIT1);
P1IES &= ~BIT0;
P1IES &= ~BIT1;
P1IE |= BIT0;
P1IE |= BIT1;
P1DIR |= BIT4;
for (;;) {
}
}
void interrupt [WDT_VECTOR] tick(void) {
while(1){
if (speed==1){
P1IFG &= ~BIT4;
if (++cnt == 200) {
cnt = 0;
P1OUT^=BIT4;
}
}
}
}
void interrupt [PORT1_VECTOR] p1Edge(void) {
if (P1IN & BIT0) {
speed=1;
P1IES &= ~BIT0;
P1IE |= BIT4; // enable P1.4 interrupts
if (speed==1){
speed=2;
P1IE |= BIT4; // enable P1.4 interrupts
}
else if(speed==2){
speed=3;
P1IE |= BIT4; // enable P1.4 interrupts
}
}
if (P1IN & BIT1) {
// P1.1 is now high -
P1IES &= ~BIT1;
if (speed==3){
speed=2;
P1IE |= BIT4; // enable P1.4 interrupts
}
else if(speed==2){
speed=1;
P1IE |= BIT4; // enable P1.4 interrupts
}
else if(speed==1)
speed=0;
P1IE |= BIT4; // enable P1.4 interrupts
}
}
Thanks in advance

Related

ATmega32's TIMER1 isn't giving an interrupt when matching

I am working on a project and I have two external interrupts (push buttons) and using TIMER1 compare match mode, I want the timer to reach the top value twice (here I have it one time only because I was trying to see where's the problem) then turn off a dc motor but it doesn't seem to fire the interrupt, the external interrupts work btw, I even tried to toggle a led in the ISR and it won't do anything. Here's the code:
uint8 volatile flag=0; //for stopping the motor
void INT0_init(void)
{
MCUCR = MCUCR | (1<ISC01) ; /*interrupt with rising edge */
MCUCR = MCUCR | (1<<ISC00);
GICR |= (1<<INT0);
DDRD = DDRD & (~(1<<PD2)); /* setting PD2 as input pin */
}
ISR (INT0_vect)
{
SET_BIT(PORTB, PB3); //when the interrupt happens the motor moves in anti clockwise direction
CLEAR_BIT(PORTB, PB4);
TIMER1_ctcMode(0x0000, 0xFFFF);
while( PIND & (1<<PD2) ) {} /*to stay in this state as long as it got pressed once */
}
void INT1_init(void)
{
MCUCR = MCUCR | (1<ISC11) ; /*interrupt with rising edge */
MCUCR = MCUCR | (1<<ISC10);
GICR |= (1<<INT1);
DDRD = DDRD & (~(1<<PD3)); /* setting PD3 as input pin */
}
ISR (INT1_vect)
{
SET_BIT(PORTB, PB3); //when the interrupt happens the motor moves in clockwise directio
CLEAR_BIT(PORTB, PB4);
TIMER1_ctcMode(0x0000, 0xFFFF); //call the timer for 8-ish seconds
while( PIND & (1<<PD3) ) {} /*to stay in this state as long as it got pressed once */
}
ISR (TIMER1_COMPA_vect) //timer isr
{
flag++;
PORTA ^=(1<<0);
_delay_ms(500);
}
int main()
{
SET_BIT(SREG,7); /* setting the i-bit */
SET_BIT(DDRB, PB3); //setting the pins as output pins of the H-bridge
SET_BIT(DDRB, PB4);
TIMER1_initCtcMode();
INT0_init(); /* initializing interrupt0 */
INT1_init(); /*initializing interrupt1 */
while (1)
{
if(flag==1)
{
TIMER1_deinit(); // to stop the timer
CLEAR_BIT(PORTB, PB3); //when the timer finishes counting stop the motor
CLEAR_BIT(PORTB, PB4);
flag=0; //set the flag to zero for the next time the timer is used
}
}
}
and here's the timer configuration:
void TIMER1_initCtcMode(void)
{
SREG= SREG | (1<<7); //setting the i-bit
TIMSK |=(1<<OCIE1A); //setting interrupt enable for timer1
TIFR &=~(1<<OCF1A);
TCCR1A |=(1<<FOC1A) ;
TCCR1A |= (1<<FOC1B); //setting the non-pwm bits
TCCR1B |=(1<<WGM12);
TCCR1B |= (1<<CS12);
TCCR1B |= (1<<CS10); //setting prescalar at 1024
TCCR1B = TCCR1B &( ~(1<<CS11));
TCCR1A &= ~(1<<COM1A0); //clearing them for non-pwm mode
TCCR1A &= ~(1<<COM1A1);
}
void TIMER1_ctcMode(volatile uint16 initialValue, volatile uint16 topValue)
{
TCNT1=initialValue; //initial value
OCR1A=topValue; //top value to reach 8.3sec
}
void TIMER1_deinit(void)
{
CLEAR_BIT(TCCR1B, CS12);
CLEAR_BIT(TCCR1B, CS10);
CLEAR_BIT(TCCR1B, CS11);
TCNT1=0;
OCR1A=0;
TIMSK &=~(1<<OCIE1A);
}

msp430 timer interrupts and port interrupts

I have written the following C code to trigger two port interrupts in order to blink a LED at different rates, I have used _delay_cycles(900000); instead I want to use a method delayMS(125); using timer interrpts, I tried as shown but Does not work , please help...
#include <msp430.h>
void initTimer_A(void);
void delayMS(int msecs);
unsigned int ofCount;
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_1MHZ; //Set DCO to 1Mhz
DCOCTL = CALDCO_1MHZ;
P1OUT=0X00;
P1DIR=0x01; //P1.0 (LED) as output)
P1IES |= 0x08; // high -> low is selected with IESx = 1.
P1IFG &= ~0x08; // To prevent an immediate interrupt, clear the flag for
P1IE |= 0x08; // Enable interrupts for P1.3
P1DIR &= ~0b00001000; // p1.3 as in
P2OUT=0X00;
P2DIR=0x01; //P2.0 (LED) as output)
P2IES |= 0x08; // high -> low is selected with IESx = 1.
P2IFG &= ~0x08; // To prevent an immediate interrupt, clear the flag for
// P2.3 before enabling the interrupt.
P2IE |= 0x08; // Enable interrupts for P1.3
P2DIR &= ~0b00001000; // p2.3 as in
_enable_interrupt();
// initTimer_A();
ofCount = 0;
P1OUT |= 0x01; //Initially the led will glow
P2OUT |= 0x01; //Initially the led will glow
while(1)
{
}
return 0;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//configure timer
void initTimer_A(void){
TACCR0 = 0;
TACCTL0 |= CCIE;
TACTL = TASSEL_2 + ID_0 + MC_1;
}
void delayMS(int msecs){
ofCount= 0;
TACCR0 = 1000-1;
while(ofCount<=msecs);
TACCR0 = 0;//stp timer
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void)
{
ofCount++;
}
//+++++++++++++++++ port vectors ++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#pragma vector = PORT1_VECTOR //PORT1 interupt vecotr name
__interrupt void P1_ISR(void) {
while(P1IN == 1){
P1OUT ^= BIT0;
This is the place where I want to change with delayMS() function using timer interrupts ….
_delay_cycles(900000);
//delayMS(125);
P1OUT ^= BIT0;
// delayMS(125);
_delay_cycles(900000);
P1IFG &= ~BIT3; } // clear the interupt flag
}
#pragma vector = PORT2_VECTOR
__interrupt void P2_ISR(void) {
while(P2IN == 1){
P1OUT ^= BIT0;
_delay_cycles(9000);
//delayMS(125);
P1OUT ^= BIT0;
_delay_cycles(9000);
//P2OUT ^= BIT0;
P2IFG &= ~BIT3; } // clear the interupt flag
}

STM32 GPIO register level input

It's actually a basic code for controlling buzzer with leds. I did with HAL libraries.But the institution I was working with wanted to do this at the register level too. But I couldn't it. It's not too complicated however i don't understand where the problem is.
My code in below.
#include "stm32f10x.h"
void SystemCoreClockConfigure(void)
{
RCC->CR |= ((uint32_t)RCC_CR_HSION); // Enable HSI
while ((RCC->CR & RCC_CR_HSIRDY) == 0); // Wait for HSI Ready
RCC->CFGR = RCC_CFGR_SW_HSI; // HSI is system clock
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); // Wait for HSI used as system clock
FLASH->ACR = FLASH_ACR_PRFTBE; // Enable Prefetch Buffer
FLASH->ACR |= FLASH_ACR_LATENCY; // Flash 1 wait state
RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // HCLK = SYSCLK
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; // APB1 = HCLK/2
RCC->CFGR |= RCC_CFGR_PPRE2_DIV1; // APB2 = HCLK
RCC->CR &= ~RCC_CR_PLLON; // Disable PLL
// PLL configuration: = HSI/2 * 12 = 48 MHz
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL);
RCC->CFGR |= (RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL12);
RCC->CR |= RCC_CR_PLLON; // Enable PLL
while((RCC->CR & RCC_CR_PLLRDY) == 0) __NOP(); // Wait till PLL is ready
RCC->CFGR &= ~RCC_CFGR_SW; // Select PLL as system clock source
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait till PLL is system clock src
}
This is the first oscillator activation part.I know that there is no problem until the main function.
In main:
int main(void)
{
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000);
RCC->APB2ENR |= (1UL << 2); /* Enable GPIOA clock */
RCC->APB2ENR |= (1UL << 4); /* Enable GPIOC clock */
// Configure the GPIO Buttons
GPIOA->CRL = 0x00000044; //1SET // GPIOA -> 0,1
GPIOC->CRL = 0x00004400; //3SET // GPIOC -> 3,2
while (1)
{
if(GPIOA->IDR == 0x0000003) // PA1 ON (Led4) //
{
GPIOC->CRH = 0x00000002; // BUZZER SET
GPIOC->BSRR = 0x00000100; // BUZZER ON
}
}
}
I'm using keil and I know that if i only set and on buzzer after
GPIOC->CRL = 0x00004400; //3SET // GPIOC -> 3,2
it's working.But with the reading input to button with GPIO->IDR(Input Data Reg.) It's not toggle or whatever i don't know.I've been stuck here for a week and it's really annoying. Heelp me !?
the code inside your while loop is completely wrong!
while(1)
{
if((GPIOA->IDR & 0x02) == 0x02) // 0x02 = 0b10 = PA1 (LED4)
{
GPIOC->BSRR = 0x100; // ON
}
else
{
GPIOC->BSRR = (0x100 << 16); // OFF
}
}
and also set the GPIOC->CRH register only once before the while loop.

Simple DC motor Speed Control with Push Button

I'm running some tests on STM32L152 by trying to control a DC motor speed by selecting 3 different speeds using a push button, as following:
ideal mode, motor is off.
push button pressed, motor runs at speed-1
push button pressed again, motor runs at speed-2
push button pressed again, motor stops.
I've already tried to run the motor directly by setting CCR1 (TIM4), and it works perfectly. so I believe the only issue is with the push button part. here's the code:
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// initialization of GPIOB, GPIOA & PWM/TIM4
void GPIO_Init()
{
// initialization of GPIOB
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; /* Reset GPIOB clock */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* Enable GPIOB clock*/
GPIOB->MODER &= ~(0x03 << (2 * 6)); /* Clear bit 12 & 13 Output mode*/
GPIOB->MODER |= 0x01 << (2 * 6); /* set as Output mode*/
GPIOB->OSPEEDR &= ~(0x03 << (2 * 6)); /* 40 MHz speed */
GPIOB->OSPEEDR |= 0x03 << (2 * 6); /* 40 MHz speed*/
GPIOB->PUPDR &= ~(1 << 6); /* NO PULL-UP PULL-DOWN*/
GPIOB->OTYPER &= ~(1 << 6); /* PUSH-PULL*/
GPIOB->AFR[0] |= 0x2 << (4 * 6);
// initialization of GPIOA
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST; /* Reset GPIOA clock*/
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* Enable GPIOA clock*/
GPIOA->MODER &= ~(0x03); /* Clear & set as input*/
GPIOA->OSPEEDR &= ~(0x03); /* 2 MHz speed */
GPIOA->OSPEEDR |= 0x01; /* 2 MHz speed */
GPIOA->PUPDR &= ~(0x03); /* No PULL-UP/DOWN */
GPIOA->OTYPER &= ~(0x1); /* PUSH-PULL */
//initialization of PWM & TIM4
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 100;
TIM4->ARR = 414; // F=2.097MHz , Fck= 2097000/(100+1)= 20.762KHz, Tpwm = 0.02, ARR= (Fck x Tpwm)-1
TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 111: PWM mode 1
TIM4->CCMR1 |= TIM_CCMR1_OC1PE;
TIM4->CR1 |= TIM_CR1_ARPE;
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->EGR |= TIM_EGR_UG;
TIM4->SR &= ~TIM_SR_UIF;
TIM4->DIER |= TIM_DIER_UIE;
TIM4->CR1 |= TIM_CR1_CEN;
}
// Delay conf
void setSysTick(void)
{
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000))
{
// Capture error
while (1)
{
};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void)
{
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks)
{
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int returnVal = 0;
int updatedpress = 0;
int buttonpress() // function to check & add, if the pushbutton is pressed
{
if (GPIOA->IDR & GPIO_IDR_IDR_0) //condition: if PA0 is set
{
Delay(500); // avoid debouncing
if (GPIOA->IDR & GPIO_IDR_IDR_0) //confirm condition: if PA0 is set
{
returnVal = 1 + updatedpress;
while (GPIOA->IDR & GPIO_IDR_IDR_0)
{
}
}
}
return returnVal;
}
int main(void)
{
GPIO_Init();
setSysTick();
while (1)
{
int buttonpress();
updatedpress = returnVal;
if (updatedpress == 1)
TIM4->CCR1 = 30;
else if (updatedpress == 2)
TIM4->CCR1 = 37;
else if (updatedpress == 3)
TIM4->CCR1 = 46;
else if (updatedpress > 3)
returnVal = 0;
}
}
When I run the code, nothing works physiclly. I tried to run the debugger and I found that it exits the buttonpress function immedtialy after reaching
if(GPIOA->IDR & GPIO_IDR_IDR_0)
Any idea why it doesn't work as it should?
The GPIO peripherals are held in reset, you should clear the reset bits:
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST
/* ... */
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST;
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOARST;
Ok it worked, and here are the corrections made:
1/ PB6 (which is connected to the DC motor) was mistakenly set as output. changed to Alternate Function.
2/ If-Conditions used for comparing the number of button-press and select motor speed is shifted to a separate function called runmotor
3/ The read instruction if(GPIOA->IDR & 0x0001) is moved into the while loop within the main function to ensure a continuous check of the pushbutton condition.
4/ Reset of GPIOs are cleared, as advised by #berendi
here's the updated code:
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// initialization of GPIOB, GPIOA & PWM/TIM4
void GPIO_Init(){
// initialization of GPIOB
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; /* Reset GPIOB clock*/
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST; /* Clear Reset */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* Enable GPIOB clock*/
GPIOB->MODER &= ~(0x03 << (2*6)); /* Clear bit 12 & 13 */
GPIOB->MODER |= 0x02 << (2*6); /* set as Alternate function*/
GPIOB->OSPEEDR &= ~(0x03<< (2*6)); /* 40 MHz speed*/
GPIOB->OSPEEDR |= 0x03<< (2*6); /* 40 MHz speed */
GPIOB->PUPDR &= ~(1<<6); /* NO PULL-UP PULL-DOWN*/
GPIOB->OTYPER &= ~(1<<6); /* PUSH-PULL*/
GPIOB->AFR[0] |= 0x2 << (4*6);
// initialization of GPIOA
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST; /* Reset GPIOA clock */
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOARST; /* Clear Reset */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* Enable GPIOA clock */
GPIOA->MODER &= ~(0x03); /* Clear & set as input */
GPIOA->OSPEEDR &= ~(0x03); /* 2 MHz speed */
GPIOA->OSPEEDR |= 0x01; /* 2 MHz speed */
GPIOA->PUPDR &= ~(0x03); /* reset PULL-DOWN */
GPIOA->OTYPER &= ~(0x1); /* PUSH-PULL */
//initialization of PWM & TIM4
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 100;
TIM4->ARR = 414; // F=2.097MHz , Fck= 2097000/(100+1)= 20.762KHz, Tpwm = 0.02, ARR= (Fck x Tpwm)-1
TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 111: PWM mode 1
TIM4->CCMR1 |= TIM_CCMR1_OC1PE;
TIM4->CR1 |= TIM_CR1_ARPE;
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->EGR |= TIM_EGR_UG;
TIM4->SR &= ~TIM_SR_UIF;
TIM4->DIER |= TIM_DIER_UIE;
TIM4->CR1 |= TIM_CR1_CEN;
}
void setSysTick(void){
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000)) {
// Capture error
while (1){};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void) {
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks){
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int buttonpress=0;
static void runmotor(void)
{
if (buttonpress ==1){
TIM4->CCR1 = 30;
return;
}
if (buttonpress ==2){
TIM4->CCR1 = 37;
return;
}
if (buttonpress ==3){
TIM4->CCR1 = 46;
return;
}
if (buttonpress > 3){
TIM4->CCR1 = 0;
buttonpress = 0;
return;
}
}
int main(void){
GPIO_Init();
setSysTick();
while (1){
if(GPIOA->IDR & 0x0001)
{
Delay(5);
if(GPIOA->IDR & 0x0001)
buttonpress = buttonpress + 1;
runmotor();
}
}
}

Interrupt with C

#include <msp430.h>
#define BUTTON BIT3 // Port 1.3
#define REDLED BIT0 // Port 1.0
#define GRNLED BIT6 // Port 1.6
#define ZERO 0x08
#define ONE 0x48
#define TWO 0x09
#define THREE 0x49
int counter = 0;
int main(void) {
// Watchdog setup
WDTCTL = WDTPW + WDTHOLD; // stop watchdog (password + hold counter)
// LED initial setup
P1DIR |= REDLED + GRNLED; // set P1.0 and P1.6 as output (1) pins
P1OUT &= ~REDLED; // Disable REDLED
P1OUT &= ~GRNLED; // Disable GRNLED
// Button setup
P1DIR &= ~BUTTON; // button is an input
P1OUT |= BUTTON; // pull-up resistor
P1REN |= BUTTON; // resistor enabled
P1IE |= 0x08; //P1.3 interrupt enable
P1IES &= ~0x08; //lower edge
P1IFG &= ~0x08; //zero flag
while(1){
}
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void){
counter += 1;
counter = (counter % 4);
switch(counter){
case 0:
P1OUT = ZERO;
break;
case 1:
P1OUT = ONE;
break;
case 2:
P1OUT = TWO;
break;
case 3:
P1OUT = THREE;
break;
}
P1IFG &= ~0x08;
}
I can not enter the ınterrup routine .I checked interrup flag ,when I push the button flag will 1 but the leds are not change ,I think that I can not enter interrup.If I can , the led must be changed.What is the wrong ?
Global interrupts are disabled by default on program's startup. You need to add code that sets the global interrupt enable (GIE) bit at the end of main(). The most platform-independent (not really) way to do it is by calling __enable_interrupts() function.
#include <msp430.h>
#include <intrinsics.h>
...
__enable_interrupts();
Alternatively, set the GIE bit directly:
__bis_status_register(GIE);
To check whether interrupts are enabled (not that inside the interrupt handler they always will be disabled by default):
if (__get_SR_register() & GIE) {
printf("interrupts enabled\n");
} else {
printf("interrupts disabled\n");
}

Resources