#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");
}
Related
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
}
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();
}
}
}
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
The code works as follows:
Button pressed: green on, red off
Button ot pressed: green off, red on
All the code samples ive seen from people online had the pullup resistor enabled when using a button to toggle between the LEDs. Is this even necessary for a code to work?
I commented the line out in my code and the only change i noticed was that it turned one the reset button. Is that what its intended for?
#include <msp430g2553.h>
#define LED0 BIT0
#define LED1 BIT6
#define BUTTON BIT3
int main(void)
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
P1DIR |= 0x40;
P1OUT &= ~0x40;
P1DIR |= 0x01;
P1OUT &= ~0x01;
P1DIR &= ~0x08;
P1SEL &= ~0x08;
//P1REN |= 0x08;
while (1) {
if ((P1IN & 0x08) == 0) {
P1OUT &= ~0x01;
P1OUT |= 0x40;
} else {
P1OUT |= 0x01;
P1OUT &= ~0x40;
}
}
return 0;
}
The code seems to work as intended but am wondering what this pullup resistor is actually intended to do?
Reset line is already pulled-up by external resistor, there is no need to pull it up with internal resistor. Reset pin also is not a GPIO (port) pin, so you basically can't enable internal pull-up for it. As for P1.3 button: some Launchpad board revisions have external pull-up resistor soldered for that button, some don't. So you should enable internal pullup for P1.3, just in case. When P1.3 button is not pressed, the circuit is open and you don't want P1.3 pin to be floating. Hence pull-up resistor required.
I found some old code of mine, it may be helpful for you. Especially pay attention to comments.
/* Program demonstrates interacting with buttons (GPIO Inputs) */
#include <msp430.h>
#define LED_RED_BIT BIT0
#define LED_GREEN_BIT BIT6
#define BUTTON_BIT BIT3
enum led_state {
RED_LIGHT = 0,
NO_LIGHT_R = 1, /* no light after red led turned off */
GREEN_LIGHT = 2,
NO_LIGHT_G = 3 /* no light after green led turned off */
};
enum led_state state; /* current state of LED state machine */
static unsigned char is_button_down;
static void init_leds(void)
{
P1DIR |= LED_GREEN_BIT | LED_RED_BIT;
P1OUT &= ~LED_GREEN_BIT;
P1OUT |= LED_RED_BIT;
state = RED_LIGHT;
}
static void init_button(void)
{
/* Since R34 is not installed -- turn on internal pull up for P1.3.
* Details: according to LaunchPad User's Guide, section 1.3:
* "Pullup resistor R34 and capacitor C24 on P1.3 removed to reduce
* the current consumption"
*/
P1OUT |= BUTTON_BIT; /* the pin is pulled up */
P1REN |= BUTTON_BIT; /* enable pull-up resistor */
is_button_down = 0;
}
/* Switches to next state of LED state machine */
static void trigger_led_sm(void)
{
switch (state) {
case RED_LIGHT:
state = NO_LIGHT_R;
P1OUT &= ~LED_RED_BIT;
break;
case NO_LIGHT_R:
state = GREEN_LIGHT;
P1OUT |= LED_GREEN_BIT;
break;
case GREEN_LIGHT:
state = NO_LIGHT_G;
P1OUT &= ~LED_GREEN_BIT;
break;
case NO_LIGHT_G:
state = RED_LIGHT;
P1OUT |= LED_RED_BIT;
break;
default:
/* Reset state machine */
init_leds();
break;
}
}
static void init(void)
{
init_leds();
init_button();
}
static void loop(void)
{
/* Button polling */
if (P1IN & BUTTON_BIT) { /* button is in released state */
if (is_button_down) {
is_button_down = 0;
/* event: button up */
}
} else { /* button is in pressed state */
if (!is_button_down) {
is_button_down = 1;
/* event: button down */
trigger_led_sm();
}
}
}
int main(void)
{
init();
for (;;)
loop();
return 0;
}
UPDATE
On schematic below you can see that "RST" pin and "P1.3" pin both have dedicated external pull-up resister: R27 for RST and R34 for P1.3. But if you have new revision of board -- R34 is not soldered there, so you have to use internal pull-up.
You can find complete schematics for your Launchpad here.
I had set MSP430F5418 P2.5 for high to low transition. But I am getting interrupts for both low-to-high and high-to-low transitions. Please my code snippet below.
P2OUT |= BIT5 /* Enable P2.5 internal resistances */
P2REN |= BIT5 /* Set up P2.5 as pull-Up resistances */
P2IES |= BIT5;
P2IE |= BIT5;
P2IFG &= ~BIT5; /* P2.5 IFG cleared */
#pragma vector=PORT2_VECTOR
__interrupt void port2_interrupt (void)
{
switch (P2IV)
{
case 0x0CU:
{
/* Do something here */
P2IFG &= ~BIT5;
break;
}
default:
{
/* No Action */
break;
}
}
}
Hans, I am not using a switch to assert the pin. It is actually done by another processor. I got a reply In TI (Texas instruments) forum that there could be a hidden high-to-low signal within a low-to-high transition and vice versa.
So, I modified my code as follows and it worked fine.
...
P2OUT |= BIT5 ; /* Enable P2.5 internal resistance */
P2REN |= BIT5; /* Set up P2.5 as pull-up resistance */
P2IES |= BIT5; /* Sets P2IFG for high to low transition */
P2IE |= BIT5; /* P2.5 interrupt enabled */
P2IFG &= ~BIT5; /* P2.5 IFG cleared */
...
#pragma vector=PORT2_VECTOR
__interrupt void port2_isr (void)
{
switch (P2IV)
{
case 0x0CU:
{
TA1CCTL0 &= ~CCIE;
TA1CCR0 = 0U;
TA1CCTL0 |= CCIE;
TA1CCTL0 &= ~CCIFG;
TA1CCR0 = TA1R + 15U;
P2IFG &= ~BIT5;
break;
}
...
...
}
}
#pragma vector = TIMER1_A0_VECTOR /* Timer1_A3 CC0 */
static __interrupt void _timer1_ao_isr (void)
{
TA1CCTL0 &= ~CCIE;
if ((P2IN & BIT5) == 0U)
{
// Got a valid high-to-low assert here!!!
}
}
Not actually an answer, just a suggestion, rename your variables to something more meaningful, two months from now you won't remember that BIT5 is the pin that you check for a high-to-low transition. You can use a define to rename BIT5 to say, HIGH_TO_LOW_PIN. You can do the same thing with the timer setup, refactor it to something more meaningful.