I'm trying to turn the led on in my tiva launchpad(tm4c123).
Current code :
while (1)
{
switch(GPIO_PORTF_DATA_R & 0x11) // 0x11 = 10001
{
case 0x00: //both switches are pressed
{
GPIO_PORTF_DATA_R = 0x02; // turn on the red led
break;
}
case 0x01: //SW1 is pressed, SW2 is not pressed
{
GPIO_PORTF_DATA_R = 0x04; // turn on the blue led
break;
}
case 0x10: //SW2 is pressed, SW1 is not pressed
{
GPIO_PORTF_DATA_R = 0x08; // turn on the green led
break;
}
default:
GPIO_PORTF_DATA_R = 0;
break;
}
}
Without this two lines of code, this is what happens :
The board start with the green led on.
When I press both or only SW2 nothing happens.
When I press SW1 the red led turn on.
Could someone explain to me why?
GPIO_PORTF_LOCK_R = 0x4C4F434B;
GPIO_PORTF_CR_R = 0x1F;
You can read your switches on your tiva launchpad like this:
SW1 = GPIO_PORTF_DATA_R&0x10; // read PF4 into SW1
SW2 = GPIO_PORTF_DATA_R&0x01; // read PF0 into SW2
Then you can check the status of those inputs and make decisions.
if (!SW1 && !SW2) { // both pressed
GPIO_PORTF_DATA_R = 0x04;
} else if (!SW1) { // SW1 pressed
GPIO_PORTF_DATA_R = 0x02;
} else if (!SW2) { // SW2 pressed
GPIO_PORTF_DATA_R = 0x08;
} else { // neither
GPIO_PORTF_DATA_R = 0x00;
}
If you look at the TM4C123GH6PM datasheet, on page 205, it says;
Protection is provided for the GPIO pins that can be used as the four
JTAG/SWD pins
If you check the signal tables on page 1329, you will see that PF0 ,where one of your switches is connected to, is one of them. So you need to unlock it.
On page 684, it says
Writing 0x4C4F.434B to the GPIOLOCK register unlocks the GPIOCR
register.
Related
I'm trying to make the PF0 and PF4 leds blink while the switches are pressed. But it simply does not turn on any leds.
I was told I needed to use two ports, I don't see why, since this can be done with only one port — in this case the port D — but it was suggested that I use the port K as well (?).
The board is a Tiva C TM4c1294nctpd
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include <inc/tm4c1294ncpdt.h>
uint32_t SW1,SW2; //
int main(void) {
while(1){
SYSCTL_RCGCGPIO_R=0X1100; // Enable port D
GPIO_PORTD_DIR_R=0X03; //enable the GPIO pin PN0,
GPIO_PORTD_DEN_R=0X03;
GPIO_PORTK_AHB_DIR_R=0;
GPIO_PORTK_AHB_DEN_R=0X03;
GPIO_PORTK_AHB_PUR_R=0X01;
SW1 = GPIO_PORTD_DATA_R&0x10; // read PF4 into SW1
SW2 = GPIO_PORTD_DATA_R&0x01; // read PF0 into SW2
if (!SW1 && !SW2) { // both pressed
GPIO_PORTD_DATA_R = 0x04;
} else if (!SW1) { // SW1 pressed
GPIO_PORTD_DATA_R = 0x02;
} else if (!SW2) { // SW2 pressed
GPIO_PORTD_DATA_R = 0x08;
} else { // neither
GPIO_PORTD_DATA_R = 0x00;
}
}
}
You have only enabled D0 and D1, but appear to be using D0, D1, D2, D3 and D4.
You have set D0 and D1 as output, but appear to be be using D1, D2, D3 as outputs.
You have set D0 as an output, but attempt to read it as an input.
The configuration of PORTK is entirely irrelevant if you are not using it.
The RCGCGPIO enables the clock for PORTN and PORTJ which you are not using at all.
I am not familiar with the part and have only briefly read the data sheet, but the the PORTD clock, direction and digital enable configuration should be as follows if the input/output code is itself correct.
SYSCTL_RCGCGPIO_R = 0x0008; // Enable port D clock
GPIO_PORTD_DIR_R = 0x0E; // D4, D0 input, D1 to D3 output.
GPIO_PORTD_DEN_R = 0x1F; // Enable D0 to D4
These initialisation settings need be done once only - before the loop, not inside it.
int main(void)
{
SYSCTL_RCGCGPIO_R = 0x0008; // Enable port D
GPIO_PORTD_DIR_R = 0x0E; // D4, D0 input, D1 to D3 output.
GPIO_PORTD_DEN_R = 0x1F; // Enable D0 to D4
for(;;)
{
uint32_t SW1 = GPIO_PORTD_DATA_R & 0x10; // read PD4 into SW1
uint32_t SW2 = GPIO_PORTD_DATA_R & 0x01; // read PD0 into SW2
if (!SW1 && !SW2) // both pressed
{
GPIO_PORTD_DATA_R = 0x04;
}
else if (!SW1) // SW1 pressed
{
GPIO_PORTD_DATA_R = 0x02;
}
else if (!SW2) // SW2 pressed
{
GPIO_PORTD_DATA_R = 0x08;
}
else // neither
{
GPIO_PORTD_DATA_R = 0x00;
}
}
}
After thought:
The comments in the presumably copy & pasted code suggest the board might be an EK-TM4C1294XL. In that case the the LEDs are called D1, D2, D3, D4 (D for diode, not _PORTD), but are on GPIOs PN1, PN0, PF4 and PF0 respectively, and the switches are on PJ0 and PJ1.
In that case perhaps the following will be more successful:
int main(void)
{
SYSCTL_RCGCGPIO_R |= (1<<5 | 1<<8 | 1<<12); // Enable port F, J and N clocks
GPIO_PORTN_DIR_R |= 0x03; // PN1 = LED0, PN0 = LED1 (Outputs)
GPIO_PORTN_DEN_R |= 0x03; // Enable PN0 and PN1
GPIO_PORTF_DIR_R |= 0x11; // PF4 = LED3, PF0 = LED4 (Outputs)
GPIO_PORTF_DEN_R |= 0x11; // Enable PF0 and PF4
GPIO_PORTJ_DIR_R &= ~0x03; // PJ0 = SW1, PJ1 = SW2 (Inputs)
GPIO_PORTJ_DEN_R &= ~0x03; // Enable PJ0 and PJ4
for(;;)
{
uint32_t SW1 = GPIO_PORTJ_DATA_R & 0x01; // read PJ0 into SW1
uint32_t SW2 = GPIO_PORTJ_DATA_R & 0x02; // read PJ1 into SW2
if (!SW1 && !SW2) // both pressed
{
GPIO_PORTF_DATA_R = 0x01; // LED4
}
else if (!SW1) // SW1 pressed
{
GPIO_PORTF_DATA_R = 0x10; // LED3
}
else if (!SW2) // SW2 pressed
{
GPIO_PORTN_DATA_R = 0x01; // LED2
}
else // neither
{
GPIO_PORTN_DATA_R = 0x02; // LED1
}
}
}
This remains broken because the code only ever switches LED's on - an it does not respect other hardware that may be connected to other pins on ports F and N; you need to add code to read-modify-write the respective pins fo reach LED you set, you need to clear the other three. I'll leave that to you - it goes beyond the original question.
Okay, so for the following code once the debugger enters the switch statement it transitions from
line 41 --> line 38 --> line 26
Then it oscillates between lines 38 and 26 perpetually. It doesn't even enter the first case statement which confuses me as I have been working on assignments until early morning. It shouldnt enter any other cases as PORTA are initialized to all zeros and the default should direct the debugger to the first case. You can even try it yourself and see what I mean.
#include <avr/io.h>
int main(void)
{
DDRA = 0x00; //PORTA = 0x00;
DDRB = 0xFF; //PORTB = 0x00;
typedef enum {
wtf, //wait for PA3 to be pressed
wth, //wait for PA2 to be pressed
dooropens, //yay
}doorstate;
doorstate state = wtf;
while (1)
{
switch(state)
{
case wtf:
if (PORTA == 0x04) {
state = wth;
PORTA = 0x00; //releases button
}
else
state = wtf;
break;
case wth:
if (PORTA == 0x02)
state = dooropens;
else
state = wtf;
break;
case dooropens:
PORTB = 0x01;
if (PORTA == 0x80) {
state = wtf;
PORTB = 0x00;
}
break;
default:
state = wtf;
}
}
}
Here are the instructions if you need a better understanding of what it's supposed to do.
A household has a digital combination deadbolt lock system on the doorway. The system has buttons on a keypad. Button 'X' connects to PA0, 'Y' to PA1, and '#' to PA2. Pressing and releasing '#', then pressing 'Y', should unlock the door by setting PB0 to 1. Any other sequence fails to unlock. Pressing a button from inside the house (PA7) locks the door (PB0=0). For debugging purposes, give each state a number, and always write the current state to PORTC (consider using the enum state variable). Also, be sure to check that only one button is pressed at a time
PORTA == 0x04)
{
state = wth;
PORTA = 0x00; //releases button
Not sure you do what you are trying to do.
You don't release a button with PORTA = 0x00
What do you think you'll be reading on PORTA if the state of 1 pin on PORTA changes?
change (PORTA == something) by (PORTA & something)
remove the line PORTA = 0x00; //releases button
Note:
DDRA = 0x00; //make port a as input
PORTA = 0x00; //disable pull-ups and make it tri state
I've changed the code for the receiver but the transmitter is pretty much the same, so in the receiver I've canceled the Interrupt and instead I read the data in a loop where I check every time for the state of the RC2IF_bit and the check is made by the same order the transmitter sends the data to make sure which port is sending data.
The problem is in simulation on proteus when I receive the data and output it on leds they work fine and the data is sent right but in the middle of the simulation when I watch it I found that they change states for a glance, for example if i send PORTA = 0X2D I receive the same value and the right leds turn-on but for a second they turn-off then they turn-on again, is this a problem in the code written.
/*This is the transmitter code*/
void UART2_TX_init (); //UART2 transmission initialization function porototype
void SEND_data (int output); //Send data function prototype
void main()
{
ANSELA = 0X00; //Disable analogue function on PORTA
ANSELE = 0X00; //Disable analogue function on PORTE
ANSELF = 0X00; //Disable analogue function on PORTF
TRISA = 0XFF; // SET PORTA AS INPUT (AUTOMATIC BUTTONS)
TRISB = 0XFF; //SET PORTB AS INPUT (OFF BUTTONS)
TRISD = 0XFF; //SET PORTD AS INPUT (MANUAL BUTTONS)
TRISE = 0XFF; //SET PORTE AS INPUT (HIGH BUTTONS)
TRISF = 0XFF; //SET PORTF AS INPUT (LOW BUTTONS)
TRISC = 0XFF; //SET PORTC AS INPUT (TRIP BUTTONS)
TRISG0_bit = 0; //set PORTC pin0 as output for MAX487 DE pin
PORTG.F0= 1; //set PORTC pin0 HIGH , set MAX487 as transmitter.
UART2_TX_init(); //call UART1 transmission initialization
while (1)
{
SEND_data(PORTA); //send data of automatic
delay_ms(10);
SEND_data(PORTB); //send data of off
delay_ms(10);
SEND_data(PORTD); //send daata of manual
delay_ms(10);
SEND_data(PORTE); //send data of high
delay_ms(10);
SEND_data(PORTF); //send data of low
delay_ms(10);
SEND_data(PORTC); //send data of TRIP
delay_ms(10);
}
}
/*This function takes the data needed to be send
as an integer. Wait for the TSR to be empty and
start the transmission*/
void SEND_data (int output)
{
while (!TRMT_TX2STA_bit){}; //checks if TSR is empty or not if empty TRMT_BIT is set and write to transmit register
TX2REG = output; //write data to be send in the transmission register
}
/*This function initializes the UART2 as an asynchronous
transmitter at a baud rate of 9600kbps*/
void UART2_TX_init ()
{
BAUD2CON = 0X08;
BRGH_TX2STA_bit = 1;
SP2BRGL = 207;
SYNC_TX2STA_bit = 0X00;
SPEN_RC2STA_bit = 0X01;
TRISG1_bit = 0X01;
TRISG2_bit = 0X01;
TXEN_TX2STA_bit = 0X01;
}
/*This is the receiver code*/
void UART2_RX_init (); // Receiver initialization function prototype
void main()
{
ANSELA = 0X00; // Disable analog function on PORTA
ANSELE = 0X00; // Disable analog function on PORTE
ANSELF = 0X00; // Disable analog function on PORTF
TRISA = 0X00; //set PORTA as output
TRISB = 0X00; //set PORTB as output
TRISD = 0X00; //set PORTD as output
TRISE = 0X00; //set PORTE as output
TRISF = 0X00; //set PORTF as output
TRISC = 0X00; //set PORTF as output
PORTA = 0x00; //clear PORTA
PORTB = 0x00; //clear PORTB
PORTD = 0x00; //clear PORTD
PORTE = 0x00; //clear PORTE
PORTF = 0x00; //clear PORTF
PORTC = 0x00; //clear PORTC
TRISG0_bit = 0x00; //set PORTC pin0 as output for MAX487 RE pin
PORTG.F0 = 0x00; // set PORTC pin0 as LOW , set MAX487 as receiver
UART2_RX_init(); //call receiver initialization function
while (1)
{
while (!RC2IF_bit) ; //check if the RCIF flag is up to tell if there is a new data
PORTA =~ RC2REG; //write the new data to the specified port
while (!RC2IF_bit) ;
PORTB =~ RC2REG;
while (!RC2IF_bit) ;
PORTD =~ RC2REG;
while (!RC2IF_bit) ;
PORTE =~ RC2REG;
while (!RC2IF_bit) ;
PORTF =~ RC2REG;
while (!RC2IF_bit) ;
PORTC =~ RC2REG;
}
}
/*This function initializes UART2 as an asynchronous
receiver at a baud rate of 9600kbps with continous
reception NO INTERRUPT ON RECEIVE*/
void UART2_RX_init ()
{
BAUD2CON = 0X08;
BRGH_TX2STA_bit = 1;
SP2BRGL = 207;
SYNC_TX2STA_bit = 0X00;
SPEN_RC2STA_bit = 0X01;
TRISG1_bit = 0X01;
TRISG2_bit = 0X01;
CREN_RC2STA_bit = 0X01;
}
First of all I want to say a few words about protocol design. Any communication protocol, if you want it to be reliable, should implement at least two things: frame synchronization and error checking. Okay, there are some specialized protocols that don't use frames and represent data as a continuous stream, but it's definitely not your case. So if you don't want to mess around with weird bugs, I highly recommend you to implement these things.
Now about your code. It looks like GET_data waits for the transmit register to be empty and writes to it one byte. I don't see anything wrong with that. But your receiver looks suspicious. You wait for the RCIF flag to be set and then read 5 times from the input register RCREG. But non-zero RCIF means that you received one byte. You can't wait for RCIF once and then read from RCREG multiple times. You should wait for RCIF before every read from RCREG.
I would be happy to give you an example of the working code, but I can't come up with a simple solution that will fit your current architecture.
I can give you example how to do it in a right way, but it will look totally different.
Some things:
the UART receive ISR should be as short as possible and just write the data into a buffer and contain absolutly not any delay routines.
use one interupt for every received byte.
start your frame with a startbyte. e.g 'S'
end your frame with a checksum byte.
do the portwrite in your mainloop after you detect a complete frame in your buffer (startbyte + databytes + correct chechsum)
#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");
}
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.